我有一个(希望)简单的软件设计问题:我想让我的实体(=获得持久化到DB的域对象)有点不可变。意思是:主体应只由服务和应用程序的每个另一部分获得创建与interface
其中只有getter方法的工作原理。Spring服务,存储库,实体设计模式建议需要
例子:
MyController
要检索MyEntity
与id=5
MyController
有权要求MyService
为了获取对象:myService.getMyEntityById(5)
MyService
会问MyEntityRepository
从数据库获取对象MyService
返回MyEntityInterface
到MyController
包装设计:
root
|--- service
| |--- MyService.java
| |--- MyServiceImpl.java
| |
| |--- MyEntity.java
| |--- MyEntityImpl.java
| |
| |--- MyEntityRepository.java
|
|
|------- web
|--- MyController.java
思路:
我的第一个想法是只需使用一个pac卡格保护的构造函数MyEntityImpl
,但这不工作我使用一些其他的库(即Orika)。因此,它必须是public
。
接下来的想法是使用MyEntity
接口。但现在我已经得到了一些问题:
问题:
的MyService(Impl)
有一个名为方法:updateMyEntityData(MyEntity e, Data data)
。现在,我不能肯定我的服务,这MyEntity
对象是真正的MyEntityImpl
一个实例内。当然,我可以做一个if(e instanceof MyEntityImpl) ...
,但是这正是我不想做的事情。
接下来的问题是:此服务方法使用MyEntityRepository
,它可以保存和检索MyEntityImpl
对象,但无法处理接口MyEntity
。作为一种变通方法,我可以做一个额外的数据库查询,但同样这不我想:
void updateMyEntityData(MyEntity e, Data data) {
MyEntityImpl impl = repo.findOne(e.getId());
impl.setData(data);
repo.saveToDB(impl);
}
这是不必要的数据库查询,因为我知道那MyEntity
是MyEntityImpl
一个实例,它已经由此服务创建,所以它必须是来自DB的对象。另一种可能是使用强制:
void updateMyEntityData(MyEntity e, Data data) {
MyEntityImpl impl = (MyEntityImpl) e;
impl.setData(data);
repo.saveToDB(impl);
}
摘要:
- 只有服务允许构建
MyEntityImpl
MyService(Impl)
必须能够修改MyEntityImpl
事后领域(指:必须有setter)- 避免不必要的数据库查询
提前谢谢!
封装受保护的setters?你也可以使用组合而不是继承 - 返回一个包装'MyEntityImpl'和'implements MyEntity'的类。它应该提供一个DAO可以用来持久化的包私有'getMyEnitityImpl'方法。如果你使用[Lombok](http://projectlombok.org/),那么[@Delegate](http://projectlombok.org/features/Delegate.html)可以在3行代码中做到这一点... –
You'重新考虑这个问题,并将复杂性引入一点或者几乎没有好处 - 一旦对象被构建,那么不可变性的各种好处就来了,那里的构造发生在这方面并不重要。强迫你的服务被用来构造域对象会增加你的应用程序的耦合性,因为你最终会传递服务而不仅仅取决于域类。类似地将接口和impl之间的域类拆分只会增加代码库的复杂性,并且不必要。 –
嗯...我最初的想法是:*没有它,一些控制器或其他服务可以创建一个'MyEntity'实例并调用'myService.updateMyEntityData(...)'*。然后我不能确定传递的对象是否真的是来自数据库的对象,或者它是否在其他地方创建。 –