Wątek przeniesiony 2018-03-14 17:10 z Algorytmy i struktury danych przez somekind.

Hermetyzacja odpowiedzialności vs. SRP

Odpowiedz Nowy wątek
2018-03-11 19:43
0

Z jednej strony mówi się że obiekt sam powinien wiedzieć co ma robić, tzn lepiej napisać kod

Client client = new Client();
client.pay();

niż

Client client = new Client();
ClientHelper.pay(client);

Z drugiej strony, mówi się też że obiekt powinien mieć jedną odpowiedzialność, jeśli ma mieć więcej, należałoby ją oddelegować do innej klasy. Powiedziawszy to, chciałbym poznać podejście forumowiczów do tematu.

Stawiam problem.

Napisz interfejs Piece która ma kilka implementacji (Pawn, Knight, Bishop, Castle, King, Queen) oraz klasę Board która ma te figury.

  • Jak mógłaby wyglądać metoda do wykonania ruchu jedną figurą (powinna być w interfejsie Piece czy w Board?)
  • Skąd figura ma wiedzieć w której miejsce może się ruszyć? (W szczególności skąd wie gdzie jest granica planszy i skąd wie które miejsce nie jest zajete?)
  • Jeśli figura ma znać swoją pozycję (x oraz y), czy może założyć że plansza ma 8x8, i użyć tego założenia do stwierdzenia czy wyjdzie poza planszę lub nie? (Czy to założenie łamie SRP? Bo niby plansza mogłaby mieć więcej?).

PS: Tylko interfejs Piece oraz klasa Board są istotne.


char mander; bool basaur;
T-Regx

Pozostało 580 znaków

2018-03-11 21:40
1

według mnie

  1. w Board bo figura nie musi (a wręcz nie powinna) wiedzieć nic o planszy
  2. nie ma wiedzieć w które miejsce konkretnie - wystarczy, że wie, że z pozycji (0,0) może się poruszyć np. na (1, 1), (2, 2), (-1, 1), (-2, 2), (1, -1), (2, -2), (-1, -1), (-2, -2) itd - czy będą to na sztywno wpisane czy liczone to od inwencji zależy. Przekażesz jej miejsce docelowe z przesunięciem do pozycji (0, 0) i tyle
  3. niezachodzi

Chcesz pomocy - pokaż kod - abrakadabra źle działa z techniką.

Pozostało 580 znaków

2018-03-11 22:49
0

Nie wiem czy jest jedna słuszna odpowiedź.

Przesuwanie figury widziałbym tak:

1) Gracz pobiera figurę
2) Gracz mówi figurze, gdzie ma się przesunąć
3) Figura weryfikuje czy ruch jest dopuszczalny.
4) Figura prosi Szachownicę o przesunięcie
5) Szachownica przesuwa figurę

 // Gracz pobiera figurę
 Figura f = szachownica->dajMiFigure(this,"C3");  
 // szachownica wie czy na C3 jest figura i czy ma taki sam kolor jak kolor gracza i na tej podstawie
 // zwraca figure, albo wali wyjątkiem: FiguraNieNalezyDoGracza, PustePole

 f->przesunNa("E4");

 // Figura wie jaki ma zakres ruchu, ale może zachodzić jedna z 2 opcji w modelu:  
 // a) Figura wie na którym polu się znajduje i na podstawie pola docelowego jest w stanie określić czy to jej zakres ruchu. 
 // b) Figura nie wie na którym polu się znajduje i musi zapytać o to szachownicę. 
 // Figura weryfikuje ruch i wali wyjątkiem jeśli żądany ruch nie jest w jej zakresie, albo prosi szachownice o przesunięcie na wybrane pole

 szachownica->przesunFigure(f,"E4");
 // szachownica wie co znajduje się "na trasie ruchu" figury i może dopuścić do przesunięcia, albo rzucić wyjątkiem

 // po przesunięciu figury, w zależności od przyjętego modelu (figura zna albo nie zna swojej pozycji)
 // Figura aktualizuje informację o tym, że została przesunięta na nowe pole 

Tyle w kwestii przesuwania.

Pozostało 580 znaków

2018-03-12 00:47
2

Chyba problem polega na tym że dzielisz 3 odpowiedzialności między dwa elementy i przy takim podziale zawszę będzie coś nie tak. Tymi samymi pionkami na tej samej planszy można grać w różne gry np. szachy, warcaby, owce i wilki a zasady gry powinny być trzymane osobno a nie upychane po kontach.
Board powinien odzwierciedlać pozycje i zapewniać API ruchów na planszy( z geometrią 2D jest więcej roboty niż się wydaje) itd. Piece implementować strategie ruchu po planszy, a trzecia klasa Game składać wszystko do kupy.
Board jest kolekcją Piece każdy Piece ma referencje do Board w którym się znajduje, tym sposobem odpowiedzialność za to czy nie wypadniemy z planszy deleguje do tego kto się o na tym zna najlepiej i nie musimy powielać kodu do ruchu w 2D. A w samych pionkach skupiamy się na w skazaniu jakie ruchu mogą wykonywać, za pomocą API w board. W Game ma referencje do border sprawdzamy wszystkie brzydkie rzeczy jak bicie w przelocie, roszady a awans pionków na figury, obowiązkowe bicia, klikanie na puste pola itp.

Czyli żeby wykonać ruch wołamy w Game.Move game wykonuje smutne sprawdzenia, pobiera Piece z planszy i pyta się go czy pole do celowe znajduje się na jego liście dozwolonych ruchów. Piece pyta się Boarer czy wykonując sekwencje ruchów x,y,z z jego API dojdzie do pola docelowego, przy założeniu bez kolizyjności, Board sprawdza czy pola są poprawne wykonuje nudne iteracje i daje odpowiedź, Game wykonturuje kolejne nudne sprawdzenia i wysyła eventy do GUI.
Ja bym to tak zrobił, w teorii tego typu rozwiązanie jest na tyle czyste że jakbyś zamienił implementacje Board np. jako wraper na jedno wymiarową tablice byte[] to nie musiał byś żadnego kodu na innych poziomach ruszać.

edytowany 1x, ostatnio: topik92, 2018-03-12 00:49
Nie wiem po co dodałeś Game tutaj, nie jest ona potrzebna imo. Po drugie ciągle problem istnieje, bo Piece wie o Board. - TomRiddle 2018-03-12 00:53

Pozostało 580 znaków

2018-03-12 03:31
8

No cóż, takie efekty nauki OOP na kotkach i pieskach. Niby "obiekty mają reprezentować elementy świata rzeczywistego", tylko to w ogóle jest nie prawda. Obiekty mają modelować rzeczywistość, czyli przedstawiać pewne jej uproszczenie pozwalające na rozwiązanie konkretnego problemu. Patrząc z punktu widzenia człowieka, że szachy to plansza i bierki niewiele się osiągnie, bo trzeba też zamodelować reguły gry oraz historię rozgrywki.

TomRiddle napisał(a):

Napisz interfejs Piece która ma kilka implementacji (Pawn, Knight, Bishop, Castle, King, Queen) oraz klasę Board która ma te figury.

  • Jak mógłaby wyglądać metoda do wykonania ruchu jedną figurą (powinna być w interfejsie Piece czy w Board?)

W żadnej z tych dwóch. Ani bierka ani plansza nie ma wiedzy wystarczającej do stwierdzenia, czy ruch jest prawidłowy.

  • Skąd figura ma wiedzieć w której miejsce może się ruszyć? (W szczególności skąd wie gdzie jest granica planszy i skąd wie które miejsce nie jest zajete?)

Nie wie - figura może dostarczyć jedynie standardowych zasad swojego ruchu.

  • Jeśli figura ma znać swoją pozycję (x oraz y), czy może założyć że plansza ma 8x8, i użyć tego założenia do stwierdzenia czy wyjdzie poza planszę lub nie? (Czy to założenie łamie SRP? Bo niby plansza mogłaby mieć więcej?).

W teorii by mogła, ale tak to może się uda weryfikować prawidłowość ruchu w kółko i krzyżyk, na pewno nie w szachach.

PS: Tylko interfejs Piece oraz klasa Board są istotne.

Pytanie, czy Piece w ogóle powinno być interfejsem, czy potrzebna jest tak dużo odrębnych klas reprezentujących bierki i czym tak naprawdę ma być Board.
Tak czy siak, do sprawdzenia prawidłowości ruchu potrzebujesz znacznie więcej danych niż wymiary planszy oraz "geograficzne" zasady ruchu bierek, bo np.:

  • nie można bić swoich bierek;
  • pionek może się ruszyć o dwa pola tylko w pierwszym ruchu;
  • nie można ruszać się przez inne bierki (z wyjątkiem skoczka);
  • mimo, że pionek rusza się tylko na wprost, a bije tylko na skos, to jednak czasami może zbić pionka stojącego obok siebie;
  • ruch nie może spowodować odsłonięcia króla;
  • nie można przeprowadzić roszady, jeśli król jest atakowany, przechodziłby przez szachowane pole lub jeśli on albo wieża już się w danej partii ruszyły.

No i do tego trzeba uwzględnić też sposób przekazywania danych o ruchu. Dobry walidator nie powinien przecież dopuścić do sytuacji, w której zostanie wykonany ruch z pustego pola, albo pola źródłowe i docelowe będą takie same. Musi też wykryć, czy ruch piona jest promocją, czy podano docelową bierkę, czy nie następuje próba promocji z nieostatniego wiersza, itd.

P.S. Rook nie Castle.


"HUMAN BEINGS MAKE LIFE SO INTERESTING. DO YOU KNOW, THAT IN A UNIVERSE SO FULL OF WONDERS, THEY HAVE MANAGED TO INVENT BOREDOM."
Z tym biciem pionka obok siebie to masz na myśli "bicie w przelocie"? - Panczo 2018-03-12 08:50
Właśnie z powodu wielu kwesti wybrałem szachy jako przykład. - TomRiddle 2018-03-12 09:40

Pozostało 580 znaków

2018-03-12 08:42
0
somekind napisał(a):
TomRiddle napisał(a):

Napisz interfejs Piece która ma kilka implementacji (Pawn, Knight, Bishop, Castle, King, Queen) oraz klasę Board która ma te figury.

  • Jak mógłaby wyglądać metoda do wykonania ruchu jedną figurą (powinna być w interfejsie Piece czy w Board?)

W żadnej z tych dwóch. Ani bierka ani plansza nie ma wiedzy wystarczającej do stwierdzenia, czy ruch jest prawidłowy.

Stosując GRASP (Information Expert), to kto ma największą wiedzę o rozmieszczeniu Figur na planszy i jest w stanie na tej podstawie określić czy ruch jest dozwolony?
(Zakładając, że zna zasady gry, jeśli nie, to pewnie potrzebuje skomunikować się z kimś, kto te zasady gry zna - edited: czyli zawężęnie odpowiedzialności w myśl zasady: High Cohesion)

edytowany 1x, ostatnio: yarel, 2018-03-12 09:12

Pozostało 580 znaków

2018-03-12 09:12
0

@yarel: myślę, że człowiek. Tylko w tym przypadku oczywiście nie ma sensu modelować całego człowieka, wystarczy jakiś jego fragment odpowiedzialny tylko za grę w szachy.


"HUMAN BEINGS MAKE LIFE SO INTERESTING. DO YOU KNOW, THAT IN A UNIVERSE SO FULL OF WONDERS, THEY HAVE MANAGED TO INVENT BOREDOM."

Pozostało 580 znaków

2018-03-12 09:17
0
somekind napisał(a):

@yarel: myślę, że człowiek. Tylko w tym przypadku oczywiście nie ma sensu modelować całego człowieka, wystarczy jakiś jego fragment odpowiedzialny tylko za grę w szachy.

Człowiek może oszukiwać i łamać reguły gry i to chyba jedyny powód dla którego nie dawałbym kontroli nad określeniem mu odpowiedzialności czy ruch jest poprawny.
Choć czasem to kuszące przesunąć figurę przeciwnika pole obok, choć wtedy to już krok do SzachoBoksu ;)

Pozostało 580 znaków

2018-03-12 09:22
0

No, a jak ludzie grają w szachy, to kto weryfikuje, czy ruch jest poprawny jak nie człowiek?

Modelując grę w szachy trzeba zrobić to samo - stworzyć wszechwiedzący walidator znający reguły oraz pamiętający historię danej rozgrywki.


"HUMAN BEINGS MAKE LIFE SO INTERESTING. DO YOU KNOW, THAT IN A UNIVERSE SO FULL OF WONDERS, THEY HAVE MANAGED TO INVENT BOREDOM."

Pozostało 580 znaków

2018-03-12 09:26
0

W niektórych językach programowania, logika nie była by ani w klasie planszy ani w klasie pionka - tam logika jest w funkcjach a klasy to czyste dane. (poczytaj o multiple dispatch)


░█░█░█░█░█░█░█░█░█░█░█░
edytowany 1x, ostatnio: krwq, 2018-03-12 09:26

Pozostało 580 znaków

2018-03-12 09:54
0

@somekind:

somekind napisał(a):
TomRiddle napisał(a):

Napisz interfejs Piece która ma kilka implementacji (Pawn, Knight, Bishop, Castle, King, Queen) oraz klasę Board która ma te figury.

  • Jak mógłaby wyglądać metoda do wykonania ruchu jedną figurą (powinna być w interfejsie Piece czy w Board?)

W żadnej z tych dwóch. Ani bierka ani plansza nie ma wiedzy wystarczającej do stwierdzenia, czy ruch jest prawidłowy.

Więc w jaki sposób powinny delegować tą decyzję do innych klas? Mógłbyś podać przykład Twojej struktury?

  • Skąd figura ma wiedzieć w której miejsce może się ruszyć? (W szczególności skąd wie gdzie jest granica planszy i skąd wie które miejsce nie jest zajete?)

Nie wie - figura może dostarczyć jedynie standardowych zasad swojego ruchu.

W szachach to może jest trywialne, ale co z grą w której jest nieskończenie wiele ruchów (albo za dużo by je zwracać), ale można je prosto walidować?

Pytanie, czy Piece w ogóle powinno być interfejsem, czy potrzebna jest tak dużo odrębnych klas reprezentujących bierki i czym tak naprawdę ma być Board.

No właśnie, to moje pytania do was.

No i do tego trzeba uwzględnić też sposób przekazywania danych o ruchu. Dobry walidator nie powinien przecież dopuścić do sytuacji, w której zostanie wykonany ruch z pustego pola, albo pola źródłowe i docelowe będą takie same. Musi też wykryć, czy ruch piona jest promocją, czy podano docelową bierkę, czy nie następuje próba promocji z nieostatniego wiersza, itd.

True

P.S. Rook nie Castle.

My bad


char mander; bool basaur;
T-Regx
edytowany 1x, ostatnio: TomRiddle, 2018-03-12 14:54

Pozostało 580 znaków

Odpowiedz
Liczba odpowiedzi na stronę

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0