L'idea alla base di OOP è che i dati e il comportamento (su quei dati) sono inseparabili e sono accoppiati all'idea di un oggetto di una classe. L'oggetto ha dati e metodi che funzionano con quello (e altri dati). Ovviamente secondo i principi di OOP, gli oggetti che sono solo dati (come le strutture C) sono considerati un anti-pattern.
Fin qui tutto bene.
Il problema è che ho notato che il mio codice sembra andare sempre più nella direzione di questo anti-pattern ultimamente. Mi sembra che più cerco di ottenere informazioni nascoste tra classi e progetti vagamente accoppiati, più le mie classi diventano un mix di dati puri senza classi di comportamento e tutto il comportamento senza classi di dati.
In genere progetto classi in modo da ridurre al minimo la consapevolezza dell'esistenza di altre classi e minimizzare la conoscenza delle interfacce di altre classi. In particolare, lo impongo dall'alto in basso, le classi di livello inferiore non conoscono le classi di livello superiore. Per esempio:
Supponiamo di avere un'API di gioco di carte generale. Hai una lezione Card. Ora questa Cardclasse deve determinare la visibilità per i giocatori.
Un modo è quello di avere boolean isVisible(Player p)in Cardclasse.
Un altro è quello di avere boolean isVisible(Card c)in Playerclasse.
Non mi piace il primo approccio in particolare poiché garantisce la conoscenza di una Playerclasse di livello superiore a una Cardclasse di livello inferiore .
Invece ho optato per la terza opzione in cui abbiamo una Viewportclasse che, dato un Playere un elenco di carte determina quali carte sono visibili.
Tuttavia questo approccio ruba entrambi Carde Playerclassi di una possibile funzione membro. Una volta che lo fai per cose diverse dalla visibilità delle carte, ti rimangono Carde le Playerclassi che contengono dati puramente poiché tutte le funzionalità sono implementate in altre classi, che sono per lo più classi senza dati, solo metodi, come Viewportsopra.
Ciò è chiaramente contrario all'idea principale di OOP.
Qual è il modo corretto? Come dovrei svolgere il compito di ridurre al minimo le interdipendenze tra le classi e minimizzare le conoscenze e l'accoppiamento presunti, ma senza concludere con uno strano design in cui tutte le classi di basso livello contengono solo dati e le classi di alto livello contengono tutti i metodi? Qualcuno ha una terza soluzione o prospettiva sul design di classe che evita l'intero problema?
PS Ecco un altro esempio:
Supponiamo che tu abbia una classe DocumentIdimmutabile, che abbia un solo BigDecimal idmembro e un getter per questo membro. Ora è necessario disporre di un metodo da qualche parte, che ha DocumentIdrestituito Documentquesto ID da un database.
Fai:
- Aggiungi il
Document getDocument(SqlSession)metodo allaDocumentIdclasse, introducendo improvvisamente la conoscenza della tua persistenza ("we're using a database and this query is used to retrieve document by id"), l'API utilizzata per accedere a DB e simili. Anche questa classe ora richiede il file JAR di persistenza solo per la compilazione. - Aggiungi un'altra classe con il metodo
Document getDocument(DocumentId id), lasciando laDocumentIdclasse come morta, nessun comportamento, classe simile a una struttura.