Podstawową ideą OOP jest to, że dane i zachowanie (na podstawie tych danych) są nierozłączne i łączy je idea obiektu klasy. Obiekt ma dane i metody, które działają z tym (i innymi danymi). Oczywiście zgodnie z zasadami OOP obiekty, które są tylko danymi (jak struktury C) są uważane za anty-wzorzec.
Na razie w porządku.
Problem w tym, że zauważyłem, że mój kod wydaje się ostatnio coraz bardziej zmierzać w kierunku tego anty-wzorca. Wydaje mi się, że im bardziej staram się uzyskać informacje ukrywające się między klasami i luźno sprzężonymi projektami, tym bardziej moje klasy stają się mieszanką czystych danych bez klas zachowań i wszystkich zachowań bez klas danych.
Generalnie projektuję klasy w sposób, który minimalizuje ich świadomość istnienia innych klas i minimalizuje ich znajomość interfejsów innych klas. Egzekwuję to szczególnie od góry, klasy niższego poziomu nie wiedzą o klasach wyższego poziomu. Na przykład:
Załóżmy, że masz ogólny interfejs API gry karcianej. Masz klasę Card
. Teraz ta Card
klasa musi określić widoczność dla graczy.
Jednym ze sposobów jest udział boolean isVisible(Player p)
w Card
zajęciach.
Innym jest mieć boolean isVisible(Card c)
na Player
zajęciach.
W szczególności nie podoba mi się pierwsze podejście, ponieważ zapewnia wiedzę o Player
klasie wyższego poziomu klasie niższej Card
.
Zamiast tego wybrałem trzecią opcję, w której mamy Viewport
klasę, która, biorąc pod uwagę a Player
i listę kart, określa, które karty są widoczne.
Jednak takie podejście pozbawia zarówno Card
i Player
zajęcia możliwej funkcji składowej. Po to zrobić dla innych rzeczy niż widoczności kart, pozostaje ci Card
i Player
klas, które zawierają wyłącznie dane jak cała funkcjonalność jest realizowana w innych klasach, które są głównie zajęcia z żadnych danych, tylko metody, podobnie jak Viewport
powyżej.
Jest to wyraźnie sprzeczne z główną ideą OOP.
Który jest właściwy sposób? Jak powinienem zająć się zadaniem zminimalizowania współzależności klas i zminimalizowania założonej wiedzy i sprzężenia, ale bez nakłaniania do dziwnego projektu, w którym wszystkie klasy niskiego poziomu zawierają tylko dane, a klasy wysokiego poziomu zawierają wszystkie metody? Czy ktoś ma jakieś trzecie rozwiązanie lub podejście do projektowania klas, które pozwala uniknąć całego problemu?
PS Oto inny przykład:
Załóżmy, że masz klasę, DocumentId
która jest niezmienna, ma tylko jednego BigDecimal id
członka i moduł pobierający dla tego członka. Teraz musisz gdzieś mieć metodę, która daje DocumentId
zwrot Document
tego identyfikatora z bazy danych.
Czy ty:
- Dodaj
Document getDocument(SqlSession)
metodę doDocumentId
klasy, nagle wprowadzając wiedzę na temat swojego persistence ("we're using a database and this query is used to retrieve document by id"
), API używanego do uzyskania dostępu do DB i tym podobnych. Również ta klasa wymaga teraz pliku JAR trwałości do kompilacji. - Dodaj inną klasę za pomocą metody
Document getDocument(DocumentId id)
, pozostawiającDocumentId
klasę martwą, bez zachowania, klasę strukturalną.