Rozważ dwie klasy Dog
i Cat
obie zgodne z Animal
protokołem (pod względem języka programowania Swift. Byłby to interfejs w Javie / C #).
Mamy ekran wyświetlający mieszaną listę psów i kotów. Istnieje Interactor
klasa, która obsługuje logikę za kulisami.
Teraz chcemy przedstawić użytkownikowi powiadomienie o potwierdzeniu, gdy chce usunąć kota. Psy należy jednak natychmiast usunąć bez żadnych powiadomień. Metoda z warunkami warunkowymi wyglądałaby następująco:
func tryToDeleteModel(model: Animal) {
if let model = model as? Cat {
tellSceneToShowConfirmationAlert()
} else if let model = model as? Dog {
deleteModel(model: model)
}
}
Jak można refaktoryzować ten kod? To oczywiście pachnie
źródło
Dog
iCat
są opisane jako klasy, podczas gdyAnimal
jest to protokół, który jest realizowany przez każdy z tych klas. Jest więc trochę niezgodności między pytaniem a odpowiedzią.Interactor
teraz od stanuCat
iDog
są obsługiwane, to może i powinien być wspólny majątekAnimal
. Robienie czegokolwiek innego wymaga późniejszego bólu głowy związanego z konserwacją.Tell vs. Ask
Podejście warunkowe, które pokazujemy, nazwalibyśmy „ zapytać ”. W tym miejscu klient konsumujący pyta „jaki jesteś?” i odpowiednio dostosowuje ich zachowanie i interakcję z obiektami.
Kontrastuje to z alternatywą, którą nazywamy „ powiedz ”. Korzystając z tell , wkładasz więcej pracy w polimorficzne implementacje, dzięki czemu kod klienta jest prostszy, bez warunków i wspólny, niezależnie od możliwych implementacji.
Ponieważ chcesz użyć alertu potwierdzającego, możesz uczynić to jawną funkcją interfejsu. Tak więc możesz mieć metodę logiczną, która opcjonalnie sprawdza u użytkownika i zwraca wartość logiczną potwierdzenia. W klasach, które nie chcą potwierdzić, po prostu zastępują
return true;
. Inne implementacje mogą dynamicznie określać, czy chcą użyć potwierdzenia.Klient używający zawsze używałby metody potwierdzenia, niezależnie od konkretnej podklasy, z którą współpracuje, co powoduje, że interakcja mówi zamiast pytać .
(Innym podejściem byłoby przesunięcie potwierdzenia do usunięcia, ale zaskoczyłoby to konsumentów, którzy oczekują, że operacja usunięcia powiedzie się.)
źródło
Interactor
teraz od stanuOkreślenie, czy konieczne jest potwierdzenie, jest obowiązkiem
Cat
klasy, więc pozwól jej wykonać tę akcję. Nie znam Kotlina, więc wyrażę rzeczy w języku C #. Mamy nadzieję, że pomysły te zostaną następnie przekazane Kotlinowi.Następnie, tworząc
Cat
instancję, dostarczasz jąTellSceneToShowConfirmationAlert
, która będzie musiała wrócić,true
jeśli OK, aby usunąć:A potem twoja funkcja staje się:
źródło
Cat
klasy. Twierdziłbym, że tam właśnie należy. Nie decyduje, w jaki sposób osiąga się to potwierdzenie (które jest wstrzykiwane) i nie usuwa się. Więc nie, nie przenosi logiki usuwania do modelu.TellSceneToShowConfirmationAlert
w instancjęCat
. W sytuacjach, gdy nie jest to łatwe (na przykład w systemie wielowarstwowym, w którym ta funkcjonalność leży na głębokim poziomie), to podejście nie byłoby dobre.Radziłbym wybrać wzór dla odwiedzających. Zrobiłem małą implementację w Javie. Nie znam Swift, ale możesz go łatwo dostosować.
Gość
Twój model
Dzwonię do gościa
Możesz mieć tyle implementacji AnimalVisitor, ile chcesz.
Przykład:
źródło