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封装原则
存储库需要知道Event
的date
才能持久化它。添加getDate
方法将违反封装原则
# 1 楼答案
您可以更改对封装原则的解释
在我们的系统中,我们需要有两个功能:一个是获取实体的内存表示并将其转换为实体的存储表示,另一个是从存储表示重构实体的功能
例如,您可能在实体上有一个返回memento的JSON表示的方法,然后在实体上有一个接受JSON表示并使用它初始化对象的构造函数
实际上,这是GoF书籍中Memento模式的应用。或者您可以将其视为从实体发送/发送到实体的消息
此消息不一定是实体数据结构的副本;它可能以不同的方式表达信息,也可能不共享所有信息,等等。但是,如果您希望稍后将信息返回到实体中,您必须能够立即将其复制出来
另一种可能有用的思考方式是:我们不存储“实体”,也不通过网络发送实体,而是通过网络发送值;这些信息被打包到一些易于理解的模式中,以便我们以后可以解包这些信息
我们认为这不违反“封装”的原因有两个:首先,纪念品是信息的副本。我们不能通过更改纪念品来更改现有实体的状态。其次,没有承诺或暗示保证memento与实体本身具有相同的数据结构
所做的是假设您可以实现实体,而不需要受持久性策略影响的代码,因为您需要能够以某种方式从数据存储中获取信息
# 2 楼答案
您需要将
Event
定义为可存储的。OOP背后的全部思想是告诉对象执行行为。您希望存储Event
的状态,但不能在不牺牲封装提供的灵活性的情况下公开该状态这与序列化对象非常相似,在序列化对象中,对象的内部状态必须写入流。这是通过让每个可序列化类定义一个
writeObject(ObjectOutputStream)
来处理的,以指定它应该如何序列化您可以提供一个
saveTo(DataStorage storage)
,让客户端知道事件中的数据可以存储在外部。与所有内部数据存储一样,这泄漏了实现,因为有人可以查看存储以查看Event
决定存储的实现细节。要读回数据,Event
将提供一个restoreFrom(DataStorage storage)
您不仅可以对客户机隐藏实现(不包括写入内部状态时不可避免的泄漏),还可以提供不同形式的
DataStorage
:可能您希望将权限保存到数据库,或者可能您希望使用DataStorageBuffer
来获取数据以供以后使用/解析/存储我们不是请求存储信息via a getter,而是告诉对象存储自己,与OOP理念保持一致