我有一個(希望)簡單的軟件設計問題:我想讓我的實體(=獲得持久化到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(...)'*。然後我不能確定傳遞的對象是否真的是來自數據庫的對象,或者它是否在其他地方創建。 –