Wpis z mikrobloga

Hej miraski. Mam problem projektowy i zastanawiam się jak go rozwiązać, żeby nie pogwałcić zasady Open-Closed Principle.

Przypuśćmy, że mamy klasę abstrakcyjną

Shape
. Mamy też kilka klas konkretnych, tj.

Circle
,

Triangle
, wszystkie dziedziczą po

Shape
i implementują metodę

draw
. Do tej pory wszystko jest zajebiście, OCP jest zachowana, super. Potrzebuję jednak metody, powiedzmy o takiej sygnaturze:

Shape getProperShape(Whatever someArgument)
która na podstawie odpowiedniej wartości argumentu zwróci mi obiekt odpowiedniej klasy dziedziczącej po Shape. A więc przykładowo jeśli dostanie argument o takiej wartości to zwróci mi

Circle
, jak o innej to

Triangle
itd.

Teraz tak, dodanie takiej metody statycznej do klasy

Shape
już będzie pogwałceniem tej reguły - bo jak dojdzie nowy kształt, powiedzmy

Square
, to ta metoda będzie wymagać zmiany, aby obsługiwała tę nową klasę.

Jak to rozwiązać? Stworzyć osobną klasę np.

ShapeFactory
? Ale to w sumie dalej będzie gwałcenie tej zasady, tylko że na innej klasie.

#programowanie #cleancode #oop
  • 14
  • Odpowiedz
  • Otrzymuj powiadomienia
    o nowych komentarzach

@Marmite: Tak czy tak gdzieś musisz mieć logikę "mapującą" wartości argumentu someArgument na konkretne klasy. Normalnie robi się to wzorcem metody fabrycznej (FactoryMethod, bardzo podobne do tego co sam wymyśliłeś z metodą statyczną), ale jak sam zauważyłeś nie jest to idealne rozwiązanie, bo również łamie OCP
  • Odpowiedz
@korri: (#) Jeśli dobrze mi się wydaje, to chyba takie rozwiązanie jak dał @MacDada: (#) pozwala nie łamać OCP no chyba że źle patrzę. Ale generalnie to chyba jest kompromis, albo OCP, albo klasa typu Factory, prawda?
  • Odpowiedz
@Marmite: Tak. To jest kompromis. Wynika to z tego, że ta logika mapowania o której wyżej pisałem, gdzieś fizycznie musi "leżeć". Jeśli leży w jednej oddzielnej klasie, to mamy klasyczne Factory - jeśli natomiast jest "rozsmarowana" po innych klasach typu providery/bezpośredno shape'y - to mamy rozwiązanie zaproponowane przez @MacDada i zachowane OCP.
  • Odpowiedz
@Marmite: Przykładowo tak działa (#php) Symfony Serializer.

Zanim dane/obiekty zostaną zserializowane np do JSONa, muszą zostać „spłaszczone” („znormalizowane”) do prostych danych. Każdy normalizator implementuje NormalizerInterface z dwiema
  • Odpowiedz
@Hauleth: (#) Z tego co widzę to właściwie sama ta funkcja jest złamaniem zasady Liskov - szkoda, że nigdzie nie ma informacji czym ją w dobry sposób zastąpić :< nawet Wujek Bob tutaj wspomina o analogicznej funkcji, ale potem już rozważa trochę inne rzeczy...
  • Odpowiedz