Search code examples
javaoopdomain-driven-designrepository-patternencapsulation

How can repository pattern fit with OOP encapsulation principle?


Let's say we have a class Event:

class Event {

  private final Long id;
  private final Date date;

  //constructor and other stuff

  public boolean hasExpired() {
    return date > today();
  }

}

As you see, its public interface is just a method hasExpired, and this uses Event internal state (date) to perform the logic.

Now, we want to save this Event to database, using a repository:

class EventRepository {

  public void saveEvent(Event event) {
    //insert into events...
  }

} 

How is this done without violating OOP encapsulation principle?

Repository needs to know Event's date in order to persist it. Adding a getDate method would violate encapsulation principle.


Solution

  • How is this done without violating OOP encapsulation principle?

    You change your interpretation of the encapsulation principle.

    Somewhere in our system we need to have two functions: one that takes the in memory representation of the entity and converts it to the stored representation of the entity, and other function that reconstitutes the entity from the stored representation.

    For instance, you might have a method on the entity that returns a JSON representation of a memento, and then a constructor on the entity that accepts a JSON representation and uses it to initialize the object.

    In effect, this is an application of the Memento pattern from the GoF book. Or you can think of it as a message that is being sent from/to the entity.

    This message isn't necessarily a copy of the data structure of the entity; it might be expressing that information in a different way, it might not be sharing all of the information, and so on. But if you want to get the information back into an entity later, you have to be able to copy it out now.

    Another way of thinking about this that may help: we don't store "entities", or send entities over the network -- we send values over the network; the information is packed into some well understood schema so that we can unpack the information later.

    The reasons that we can argue that this isn't a violation of "encapsulation" is two fold: first, the memento is a copy -- a deep copy -- of the information. We can't change the existing entity's state by changing the memento. Second, there's no promise or implied guarantee that the memento has the same data structure as the entity itself.

    What does fall over is the assumption that you can implement the entity with no code that is influenced by your persistence strategy, because you need to be able to get the information out of the data store somehow.