The basic idea behind OOP is that data and behavior (upon that data) are inseparable and they are coupled by the idea of an object of a class. Object have data and methods that work with that (and other data). Obviously by the principles of OOP, objects that are just data (like C structs) are considered an anti-pattern.
So far so good.
The problem is I have noticed that my code seems to be going more and more in the direction of this anti-pattern lately. Seems to me that the more I try to achieve information hiding between classes and loosely coupled designs, the more my classes get to be a mix of pure data no behavior classes and all behavior no data classes.
I generally design classes in a way which minimizes their awareness of other classes' existence and minimizes their knowledge of other classes' interfaces. I especially enforce this in a top-down fashion, lower level classes don't know about higher level classes. E.g.:
Suppose you have a general card game API. You have a class
Card. Now this
Card class needs to determine visibility to players.
One way is to have
boolean isVisible(Player p) on
Another is to have
boolean isVisible(Card c) on
I dislike the first approach in particular as it grants knowledge about higher level
Player class to a lower level
Instead I opted for the third option where we have a
Viewport class which, given a
Player and a list of cards determines which cards are visible.
However this approach robs both
Player classes of a possible member function. Once you do this for other stuff than visibility of cards, you are left with
Player classes which contain purely data as all functionality is implemented in other classes, which are mostly classes with no data, just methods, like the
This is clearly against the principal idea of OOP.
Which is the correct way? How should I go about the task of minimizing class interdependencies and minimizing assumed knowledge and coupling, but without winding up with weird design where all the low level classes contain data only and high level classes contain all the methods? Does anyone have any third solution or perspective on class design which avoids the whole problem?
P.S. Here's another example:
Suppose you have class
DocumentId which is immutable, only has a single
BigDecimal id member and a getter for this member. Now you need to have a method somewhere, which given a
Document for this id from a database.
Document getDocument(SqlSession)method to
DocumentIdclass, suddenly introducing knowledge about your persistence (
"we're using a database and this query is used to retrieve document by id"), the API used to access DB and the like. Also this class now requires persistence JAR file just to compile.
- Add a some other class with method
Document getDocument(DocumentId id), leaving
DocumentIdclass as dead, no behavior, struct-like class.