Zadaniem w mojej klasie inżynierii oprogramowania jest zaprojektowanie aplikacji, która może grać w różne formy konkretnej gry. Ta gra to Mancala, niektóre z nich nazywane są Wari lub Kalah. Te gry różnią się w niektórych aspektach, ale na moje pytanie ważne jest, aby wiedzieć, że gry mogą się różnić w następujący sposób:
- Sposób, w jaki obsługiwany jest wynik ruchu
- Sposób określania końca gry
- Sposób określania zwycięzcy
Pierwszą rzeczą, jaka przyszła mi do głowy, aby to zaprojektować, było użycie wzorca strategii, mam różne algorytmy (rzeczywiste zasady gry). Projekt może wyglądać następująco:

Pomyślałem wtedy, że w grze Mancala i Wari sposób określania zwycięzcy jest dokładnie taki sam, a kod byłby duplikowany. Nie sądzę, że jest to z definicji naruszenie zasady „jedna zasada, jedno miejsce” lub zasada SUCHA postrzegana jako zmiana zasad dla Mancala nie oznacza automatycznie, że zasada ta powinna zostać również zmieniona w Wari. Niemniej jednak dzięki opiniom otrzymanym od mojego profesora miałem wrażenie, że znalazłem inny projekt.
Potem wymyśliłem:

Każda gra (Mancala, Wari, Kalah, ...) miałaby po prostu atrybut typu interfejsu każdej reguły, tj. WinnerDeterminerI jeśli istnieje wersja Mancala 2.0, która jest taka sama jak Mancala 1.0, z wyjątkiem tego, w jaki sposób zostanie wyłoniony zwycięzca, może po prostu użyj wersji Mancala.
Myślę, że wdrożenie tych zasad jako wzorca strategii jest z pewnością prawidłowe. Ale prawdziwy problem pojawia się, gdy chcę go dalej projektować.
Czytając o wzorcu metody szablonu, od razu pomyślałem, że można go zastosować do tego problemu. Czynności wykonywane, gdy użytkownik wykonuje ruch, są zawsze takie same i w tej samej kolejności, a mianowicie:
- osadzaj kamienie w dołkach (jest to takie samo dla wszystkich gier, więc byłoby zaimplementowane w samej metodzie szablonu)
- określić wynik ruchu
- ustalić, czy gra zakończyła się z powodu poprzedniego ruchu
- jeśli gra się zakończy, określ, kto wygrał
Te trzy ostatnie kroki są zgodne ze schematem mojej strategii opisanym powyżej. Mam problem z połączeniem tych dwóch. Jednym z możliwych rozwiązań, które znalazłem, byłoby porzucenie wzorca strategii i wykonanie następujących czynności:

Naprawdę nie widzę różnicy w projekcie między wzorem strategii a tym? Ale jestem pewien, że muszę użyć metody szablonu (chociaż byłem równie pewien, że muszę użyć wzorca strategii).
Nie potrafię też ustalić, kto byłby odpowiedzialny za utworzenie TurnTemplateobiektu, podczas gdy przy wzorcu strategicznym czuję, że mam rodziny obiektów (trzy reguły), które można łatwo utworzyć za pomocą abstrakcyjnego wzorca fabrycznego. Chciałbym mieć wtedy MancalaRuleFactory, WariRuleFactoryitp a oni stworzyć odpowiednie instancje zasad i ręce mi się RuleSetobiekt.
Powiedzmy, że używam strategii + abstrakcyjnego wzorca fabrycznego i mam RuleSetobiekt, który ma algorytmy dla trzech reguł. Jedynym sposobem, w jaki mogę nadal używać wzorca metody szablonu w tym celu, jest przekazanie tego RuleSetobiektu do mojego TurnTemplate. „Problem”, który się wtedy pojawia, polega na tym, że nigdy nie potrzebowałbym moich konkretnych implementacji TurnTemplate, klasy te stałyby się przestarzałe. W moich chronionych metodach TurnTemplatemogłem po prostu wywołać ruleSet.determineWinner(). W rezultacie TurnTemplateklasa nie byłaby już abstrakcyjna, ale musiałaby stać się konkretna, czy w takim razie nadal jest wzorcem metody szablonu?
Podsumowując, czy myślę we właściwy sposób, czy brakuje mi czegoś łatwego? Jeśli jestem na dobrej drodze, jak połączyć wzorzec strategii i wzorzec metody szablonu?