Wiem, że to stare pytanie, ale myślę, że mam inny ciekawy przykład, który niedawno wdrożyłem.
Jest to bardzo praktyczny przykład wzorca strategii stosowanego w systemie dostarczania dokumentów.
Miałem system dostarczania PDF, który otrzymał archiwum zawierające wiele dokumentów i kilka metadanych. Na podstawie metadanych zdecydował, gdzie umieścić dokument; powiedzmy, w zależności od danych, mogę zapisać dokument A
, B
lub C
magazynowych systemów lub mieszankę tych trzech.
Różni klienci korzystali z tego systemu i mieli różne wymagania dotyczące wycofywania / obsługi błędów w przypadku błędów: jeden chciał, aby system dostarczania zatrzymał się przy pierwszym błędzie, zostawił wszystkie dokumenty już dostarczone w swoich magazynach, ale zatrzymał proces i nie dostarczał niczego innego ; inny chciał, żeby B
w przypadku błędów przy składowaniu został wycofany C
, ale zostawił to, co zostało już dostarczone A
. Łatwo sobie wyobrazić, że trzeci czy czwarty też będzie miał inne potrzeby.
Aby rozwiązać ten problem, utworzyłem podstawową klasę dostarczania, która zawiera logikę dostarczania oraz metody wycofywania danych ze wszystkich magazynów. Metody te nie są w rzeczywistości wywoływane bezpośrednio przez system dostarczania w przypadku błędów. Zamiast tego klasa używa Dependency Injection, aby otrzymać klasę „Rollback / Error Handling Strategy” (opartą na kliencie korzystającym z systemu), która jest wywoływana w przypadku błędów, która z kolei wywołuje metody wycofywania zmian, jeśli jest to odpowiednie dla tej strategii.
Klasa dostawy sama zgłasza, co się dzieje w klasie strategii (jakie dokumenty zostały dostarczone do jakich magazynów i jakie awarie się wydarzyły), a gdy wystąpi błąd, pyta strategię, czy kontynuować, czy nie. Jeśli strategia mówi „stop it”, klasa wywołuje metodę „cleanUp” strategii, która używa wcześniej zgłoszonych informacji, aby zdecydować, które metody wycofywania wywołać z klasy dostarczającej lub po prostu nic nie robić.
rollbackStrategy.reportSuccessA(...);
rollbackStrategy.reportFailureB(...);
if (rollbackStrategy.mustAbort()) {
rollbackStrategy.rollback(); // rollback whatever is needed based on reports
return false;
}
Więc mam teraz dwie różne strategie: jedna to QuitterStrategy
(która kończy pracę po pierwszym błędzie i nic nie czyści), a druga to MaximizeDeliveryToAStrategy
(która stara się jak najbardziej nie przerywać procesu i nigdy nie przywracać zawartości dostarczonej do pamięci) A
, ale wycofuje rzeczy z, B
jeśli dostawa się C
nie powiedzie).
Z mojego zrozumienia jest to jeden z przykładów wzorca strategii. Jeśli (tak, czytasz) myślisz, że się mylę, skomentuj poniżej i daj mi znać. Ciekawi mnie, co oznaczałoby „czyste” wykorzystanie wzorca strategii i jakie aspekty mojej realizacji naruszają definicję. Myślę, że wygląda to trochę zabawnie, ponieważ interfejs strategii jest nieco gruby. Wszystkie przykłady, które widziałem do tej pory, wykorzystują tylko jedną metodę, ale nadal uważam, że zawiera ona algorytm (jeśli część logiki biznesowej można uznać za algorytm, a myślę, że tak jest).
Ponieważ strategia jest również powiadamiana o zdarzeniach podczas realizacji dostawy, można ją również uznać za obserwatora , ale to już inna historia.
Po przeprowadzeniu krótkich badań wydaje się, że jest to „wzorzec złożony” (jak MVC, wzorzec wykorzystujący wiele wzorców projektowych pod spodem w określony sposób) zwany Doradcą . Jest doradcą, czy dostarczanie powinno być kontynuowane, czy nie, ale jest również aktywną obsługą błędów, ponieważ może wycofać dane, gdy zostanie o to poproszony.
W każdym razie, jest to dość złożony przykład, który może sprawić, że poczujesz, że użycie wzorca strategii jest zbyt proste / głupie. W połączeniu z innymi wzorami może być naprawdę złożony i jeszcze bardziej przydatny.