Object-Oriented Design – Zero Behavior Objects in OOP

object-oriented

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 Card class.

Another is to have boolean isVisible(Card c) on Player class.

I dislike the first approach in particular as it grants knowledge about higher level Player class to a lower level Card class.

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 Card and Player classes of a possible member function. Once you do this for other stuff than visibility of cards, you are left with Card and 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 Viewport above.

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 DocumentId returns Document for this id from a database.

Do you:

  • Add Document getDocument(SqlSession) method to DocumentId class, 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 DocumentId class as dead, no behavior, struct-like class.

Best Answer

What you describe is known as an anemic domain model. As with many OOP design principles (like Law of Demeter etc.), it's not worth bending over backwards just to satisfy a rule.

Nothing wrong about having bags of values, as long as they don't clutter the entire landscape and don't rely on other objects to do the housekeeping they could be doing for themselves.

It would certainly be a code smell if you had a separate class just for modifying properties of Card - if it could be reasonably expected to take care of them on its own.

But is it really a job of a Card to know which Player it is visible to?

And why implement Card.isVisibleTo(Player p), but not Player.isVisibleTo(Card c)? Or vice versa?

Yes, you can try to come up with some sort of a rule for that as you did - like Player being more high level than a Card (?) - but it's not that straightforward to guess and I'll have to look in more than one place to find the method.

Over time it can lead to a rotten design compromise of implementing isVisibleTo on both Card and Player class, which I believe is a no-no. Why so? Because I already imagine the shameful day when player1.isVisibleTo(card1) will return a different value than card1.isVisibleTo(player1). I think - it's subjective - this should be made impossible by design.

Mutual visibility of cards and players should better be governed by some sort of a context object - be it Viewport, Deal or Game.

It's not equal to having global functions. After all, there may be many concurrent games. Note that the same card can be used simultaneously on many tables. Shall we create many Card instances for each ace of spade?

I might still implement isVisibleTo on Card, but pass a context object to it and make Card delegate the query. Program to interface to avoid high coupling.

As for your second example - if the document ID consists only of a BigDecimal, why create a wrapper class for it at all?

I'd say all you need is a DocumentRepository.getDocument(BigDecimal documentID);

By the way, while absent from Java, there are structs in C#.

See

for reference. It's a highly object-oriented language, but noone makes a big deal out of it.

Related Topic