有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java存储库模式如何适应OOP封装原则?

假设我们有一个类Event

class Event {

  private final Long id;
  private final Date date;

  //constructor and other stuff

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

}

如您所见,它的公共接口只是一个方法hasExpired,它使用Event内部状态(date)来执行逻辑

现在,我们希望使用存储库将此Event保存到数据库:

class EventRepository {

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

} 

如何做到这一点而不违反OOP封装原则

存储库需要知道Eventdate才能持久化它。添加getDate方法将违反封装原则


共 (2) 个答案

  1. # 1 楼答案

    How is this done without violating OOP encapsulation principle?

    您可以更改对封装原则的解释

    在我们的系统中,我们需要有两个功能:一个是获取实体的内存表示并将其转换为实体的存储表示,另一个是从存储表示重构实体的功能

    例如,您可能在实体上有一个返回memento的JSON表示的方法,然后在实体上有一个接受JSON表示并使用它初始化对象的构造函数

    实际上,这是GoF书籍中Memento模式的应用。或者您可以将其视为从实体发送/发送到实体的消息

    此消息不一定是实体数据结构的副本;它可能以不同的方式表达信息,也可能不共享所有信息,等等。但是,如果您希望稍后将信息返回到实体中,您必须能够立即将其复制出来

    另一种可能有用的思考方式是:我们不存储“实体”,也不通过网络发送实体,而是通过网络发送;这些信息被打包到一些易于理解的模式中,以便我们以后可以解包这些信息

    我们认为这不违反“封装”的原因有两个:首先,纪念品是信息的副本。我们不能通过更改纪念品来更改现有实体的状态。其次,没有承诺或暗示保证memento与实体本身具有相同的数据结构

    所做的是假设您可以实现实体,而不需要受持久性策略影响的代码,因为您需要能够以某种方式从数据存储中获取信息

  2. # 2 楼答案

    您需要将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);
        }
    }
    

    我们不是请求存储信息via a getter,而是告诉对象存储自己,与OOP理念保持一致