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 Cardklasa musi określić widoczność dla graczy.
Jednym ze sposobów jest udział boolean isVisible(Player p)w Cardzajęciach.
Innym jest mieć boolean isVisible(Card c)na Playerzajęciach.
W szczególności nie podoba mi się pierwsze podejście, ponieważ zapewnia wiedzę o Playerklasie wyższego poziomu klasie niższej Card.
Zamiast tego wybrałem trzecią opcję, w której mamy Viewportklasę, która, biorąc pod uwagę a Playeri listę kart, określa, które karty są widoczne.
Jednak takie podejście pozbawia zarówno Cardi Playerzajęcia możliwej funkcji składowej. Po to zrobić dla innych rzeczy niż widoczności kart, pozostaje ci Cardi Playerklas, 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 Viewportpowyż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ę, DocumentIdktóra jest niezmienna, ma tylko jednego BigDecimal idczłonka i moduł pobierający dla tego członka. Teraz musisz gdzieś mieć metodę, która daje DocumentIdzwrot Documenttego identyfikatora z bazy danych.
Czy ty:
- Dodaj
Document getDocument(SqlSession)metodę doDocumentIdklasy, 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ącDocumentIdklasę martwą, bez zachowania, klasę strukturalną.