Krótko mówiąc, za każdym razem, gdy używasz „nowego”, ściśle łączysz klasę zawierającą ten kod z tworzonym obiektem; aby utworzyć instancję jednego z tych obiektów, klasa wykonująca instancję musi wiedzieć o instancji konkretnej klasy. Tak więc, używając „nowego”, powinieneś rozważyć, czy klasa, w której umieszczasz instancję, jest „dobrym” miejscem dla tej wiedzy i czy jesteś gotów wprowadzić zmiany w tym obszarze, jeśli forma instancja obiektu miała się zmienić.
Nie zawsze należy unikać ciasnego łączenia, czyli obiektu posiadającego wiedzę o innej konkretnej klasie; na pewnym poziomie coś, GDZIEŚ, musi wiedzieć, jak stworzyć ten obiekt, nawet jeśli wszystko inne zajmuje się tym obiektem, otrzymując jego kopię z innego miejsca. Jednak gdy tworzona klasa ulega zmianie, każda klasa, która wie o konkretnej implementacji tej klasy, musi zostać zaktualizowana, aby poprawnie radzić sobie ze zmianami tej klasy.
Pytanie, które powinieneś zawsze zadać, brzmi: „Czy posiadanie tej klasy będzie wiedziała, jak utworzyć tę drugą klasę, która stanie się obowiązkiem podczas utrzymywania aplikacji?” Obie główne metodologie projektowania (SOLID i GRASP) zwykle odpowiadają „tak” z nieco innych powodów. Są to jednak tylko metodologie i oba mają skrajne ograniczenie, że nie zostały sformułowane w oparciu o wiedzę o twoim unikalnym programie. W związku z tym mogą one popełniać błędy tylko po stronie ostrożności i zakładać, że każdy punkt ścisłego sprzężenia spowoduje w ODWRÓCENIU problem związany z wprowadzeniem zmian w jednej lub obu stronach tego punktu. Musisz podjąć ostateczną decyzję, wiedząc o trzech rzeczach; najlepsza praktyka teoretyczna (polegająca na luźnym powiązaniu wszystkiego, ponieważ wszystko może się zmienić); koszty wdrożenia teoretycznych najlepszych praktyk (które mogą obejmować kilka nowych warstw abstrakcji, które ułatwią jeden rodzaj zmiany, a przeszkadzają w innym); a realne prawdopodobieństwo, że przewidywany rodzaj zmian będzie kiedykolwiek konieczny.
Kilka ogólnych wskazówek:
Unikaj ścisłego łączenia między skompilowanymi bibliotekami kodów. Interfejs między bibliotekami DLL (lub EXE i jego bibliotekami DLL) jest głównym miejscem, w którym ścisłe sprzężenie będzie niekorzystne. Jeśli zmienisz klasę A w DLL X, a klasa B w głównym EXE wie o klasie A, musisz ponownie skompilować i zwolnić oba pliki binarne. W obrębie jednego pliku binarnego ściślejsze sprzężenie jest ogólnie bardziej dopuszczalne, ponieważ cały plik binarny musi zostać zrekonstruowany pod kątem każdej zmiany. Czasami konieczność odbudowania wielu plików binarnych jest nieunikniona, ale powinieneś tak ustrukturyzować swój kod, abyś mógł go w miarę możliwości uniknąć, szczególnie w sytuacjach, w których przepustowość jest na wysokim poziomie (takich jak wdrażanie aplikacji mobilnych; wrzucanie nowej biblioteki DLL podczas aktualizacji jest znacznie tańsze niż wypychanie całego programu).
Unikaj ścisłego powiązania między głównymi „centrami logicznymi” twojego programu. Możesz myśleć o dobrze ustrukturyzowanym programie składającym się z poziomych i pionowych przekrojów. Wycinki poziome mogą być tradycyjnymi warstwami aplikacji, takimi jak interfejs użytkownika, kontroler, domena, DAO, dane; pionowe wycinki mogą być zdefiniowane dla poszczególnych okien lub widoków, lub dla indywidualnych „historii użytkowników” (takich jak utworzenie nowego rekordu jakiegoś podstawowego typu). Kiedy wykonujesz połączenie, które przesuwa się w górę, w dół, w lewo lub w prawo w dobrze zorganizowanym systemie, powinieneś ogólnie streścić to połączenie. Na przykład, gdy sprawdzanie poprawności wymaga pobrania danych, nie powinno ono mieć bezpośredniego dostępu do bazy danych, ale powinno wywołać interfejs do pobierania danych, który jest wspierany przez rzeczywisty obiekt, który wie, jak to zrobić. Gdy niektóre elementy interfejsu użytkownika muszą wykonywać zaawansowaną logikę obejmującą inne okno, powinno to wyzwolić wyzwolenie tej logiki poprzez zdarzenie i / lub wywołanie zwrotne; nie musi wiedzieć, co zostanie w wyniku tego zrobione, pozwalając ci zmienić to, co zostanie zrobione, bez zmiany kontroli, która je wyzwala.
W każdym razie zastanów się, jak łatwa lub trudna będzie zmiana i jak prawdopodobne będzie ta zmiana. Jeśli obiekt, który tworzysz, jest używany tylko z jednego miejsca i nie przewiduje się takiej zmiany, wówczas ścisłe sprzężenie jest ogólnie bardziej dopuszczalne, aw tej sytuacji może nawet przewyższyć luźne sprzężenie. Luźne sprzężenie wymaga abstrakcji, która jest dodatkową warstwą, która zapobiega zmianie obiektów zależnych, gdy implementacja zależności musi ulec zmianie. Jeśli jednak sam interfejs musi się zmienić (dodanie nowego wywołania metody lub dodanie parametru do istniejącego wywołania metody), interfejs faktycznie zwiększa ilość pracy niezbędnej do wprowadzenia zmiany. Musisz rozważyć prawdopodobieństwo różnych rodzajów zmian wpływających na projekt,