Как шаблон репозитория может соответствовать принципу инкапсуляции OOP? - PullRequest
1 голос
/ 25 апреля 2020

Допустим, у нас есть класс Event:

class Event {

  private final Long id;
  private final Date date;

  //constructor and other stuff

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

}

Как видите, его интерфейс publi c - это просто метод hasExpired, и в нем используется внутреннее состояние Event (date) для выполнения логи c.

Теперь мы хотим сохранить Event в базе данных, используя репозиторий:

class EventRepository {

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

} 

Как это сделать, не нарушая OOP принцип инкапсуляции?

Хранилище должно знать Event s date, чтобы сохранить его. Добавление метода getDate нарушит принцип инкапсуляции.

Ответы [ 2 ]

0 голосов
/ 26 апреля 2020

Вы должны определить Event для хранения. Вся идея OOP заключается в том, чтобы указывать объектам выполнять поведение. Вы хотите сохранить состояние Event, но не можете предоставить его без ущерба для гибкости, которую обеспечивает инкапсуляция.

Это очень похоже на сериализацию объектов, где их внутреннее состояние должно быть записано в поток. Это достигается тем, что каждый сериализуемый класс определяет writeObject(ObjectOutputStream) для указания способа его сериализации.

Вы можете предоставить saveTo(DataStorage storage), чтобы клиенты знали, что данные из события могут храниться извне. Как и во всех хранилищах внутренних данных, это приводит к утечке реализации, так как кто-то может просмотреть хранилище, чтобы посмотреть, какие детали реализации Event решили сохранить. Чтобы прочитать данные обратно, Event предоставит restoreFrom(DataStorage storage).

Мало того, что вы будете хранить реализацию скрытой от клиентов (не считая утечки из записи внутреннего состояния, это неизбежно при записи внутреннего состояния), но Вы можете предоставить различные формы DataStorage: возможно, вы хотите сохранить права в базе данных, или, возможно, вы хотите DataStorageBuffer для получения данных для последующего использования / анализа / хранения.

class Event {
    private final Long id;
    private final Date date;

    public Event(Long id, Date date) {
        this.id = id;
        this.date = date;
    }

    public void saveTo(DataStorage storage) {
        // Add state to storage
    }

    public static Event readFrom(DataStorage storage) {
        Long id = ...; // read from storage
        Date date = ...;

        return new Event(id, date);
    }
}

Скорее чем запрашивать информацию для хранения через получатель , мы говорим объекту сохранять себя, оставаясь в соответствии с философией OOP.

0 голосов
/ 25 апреля 2020

Как это сделать без нарушения принципа инкапсуляции OOP?

Вы меняете свою интерпретацию принципа инкапсуляции.

Где-то в нашей системе нам нужно иметь две функции: одна, которая принимает представление в памяти объект и преобразует его в сохраненное представление объекта, а также другую функцию, которая восстанавливает объект из сохраненного представления.

Например, у вас может быть метод для объекта, который возвращает JSON представление memento, а затем конструктор объекта, который принимает представление JSON и использует его для инициализации объекта.

По сути, это приложение шаблона Memento из книги GoF. Или вы можете думать о нем как о сообщении, которое отправляется от объекта к объекту.

Это сообщение не обязательно является копией структуры данных объекта; это может быть выражение этой информации по-другому, это может не делиться всей информацией, и так далее. Но если вы хотите получить информацию обратно в сущность позже, вы должны иметь возможность скопировать ее сейчас.

Другой способ думать об этом, который может помочь: мы не храним «сущности», или отправлять объекты по сети - мы отправляем значения по сети; информация упакована в какую-то хорошо понятную схему, чтобы мы могли распаковать ее позже.

Причины, по которым мы можем утверждать, что это не является нарушением «инкапсуляции», двояки: во-первых, сувенир копия - глубокая копия - информации. Мы не можем изменить состояние существующей сущности, изменив память. Во-вторых, нет никаких обещаний или подразумеваемых гарантий, что память имеет ту же структуру данных, что и сама сущность.

То, что делает , - это предположение, что вы можете реализовать сущность без кода, который зависит от вашей стратегии персистентности, потому что вам нужно каким-то образом получить информацию из хранилища данных.

...