Kiedy tylko mogę, staram się ograniczyć komunikację między obiektami do modelu żądania i odpowiedzi. Istnieje domniemane częściowe uporządkowanie obiektów w moim programie, tak że pomiędzy dowolnymi dwoma obiektami A i B może istnieć sposób, aby A bezpośrednio lub pośrednio wywołał metodę B lub B mógł bezpośrednio lub pośrednio wywołać metodę A , ale A i B nigdy nie mogą wzajemnie nazywać się metodami. Czasami oczywiście chcesz mieć wsteczną komunikację z dzwoniącym metody. Lubię to robić na kilka sposobów i żaden z nich nie jest wywołaniem zwrotnym.
Jednym ze sposobów jest dołączenie większej ilości informacji do wartości zwracanej wywołania metody, co oznacza, że kod klienta może zdecydować, co z nim zrobić, gdy procedura zwróci mu kontrolę.
Innym sposobem jest wywołanie wspólnego obiektu potomnego. To znaczy, jeśli A wywołuje metodę na B, a B musi przekazać pewne informacje do A, B wywołuje metodę na C, gdzie A i B mogą wywoływać C, ale C nie może wywoływać A lub B. Obiekt A byłby wtedy odpowiedzialny za uzyskanie informacji z C po tym, jak B zwraca kontrolę do A. Zauważ, że tak naprawdę nie różni się to tak naprawdę od pierwszego sposobu, jaki zaproponowałem. Obiekt A nadal może pobierać informacje tylko z wartości zwracanej; żadna z metod obiektu A nie jest wywoływana przez B lub C. Odmianą tej sztuczki jest przekazanie C jako parametru metody, ale nadal obowiązują ograniczenia dotyczące relacji C do A i B.
Ważne pytanie brzmi: dlaczego nalegam na robienie tego w ten sposób. Istnieją trzy główne powody:
- Utrzymuje moje obiekty luźniej sprzężone. Moje obiekty mogą zawierać inne obiekty, ale nigdy nie będą zależeć od kontekstu obiektu wywołującego, a kontekst nigdy nie będzie zależał od obiektów otoczonych.
- To sprawia, że moja kontrola jest łatwa do uzasadnienia. Miło jest móc założyć, że jedynym kodem, który może zmienić stan wewnętrzny
self
podczas wykonywania metody, jest ta jedna metoda i żadna inna. Jest to ten sam rodzaj rozumowania, który może prowadzić do umieszczenia muteksów na współbieżnych obiektach.
- Chroni niezmienniki w enkapsulowanych danych moich obiektów. Metody publiczne mogą zależeć od niezmienników, a niezmienniki te mogą zostać naruszone, jeśli jedną metodę można wywołać zewnętrznie, podczas gdy inna już działa.
Nie jestem przeciwko wszelkim zastosowaniom wywołań zwrotnych. Zgodnie z moją polityką, aby nigdy nie „wywoływać obiektu wywołującego”, jeśli obiekt A wywołuje metodę na B i przekazuje do niej wywołanie zwrotne, wywołanie zwrotne może nie zmienić stanu wewnętrznego A, i obejmuje obiekty otoczone przez A i obiekt obiekty w kontekście A. Innymi słowy, wywołanie zwrotne może wywoływać metody tylko na obiektach przekazanych mu przez B. W efekcie wywołanie zwrotne podlega takim samym ograniczeniom jak B.
Ostatnim luźnym zakończeniem jest to, że pozwolę na wywołanie dowolnej czystej funkcji, niezależnie od tego częściowego uporządkowania, o którym mówiłem. Czyste funkcje różnią się nieco od metod, ponieważ nie mogą się zmienić lub zależą od stanu zmiennego lub efektów ubocznych, więc nie martw się o to, że dezorientują.