哪种设计模式更适合保存/删除数据?为什么?
我无法在以下两种模式之间做出决定,例如。保存一个数据对象(在我的例子中是bean)。这两个选项是:
1st
abstract class DataService {
protected void save(Object data){
//persist the data
}
}
//the service for Project objects
class ProjectService extends DataService {
public void saveProject(Project prj, Object... args /*other save options*/ ){
// some preprocessing, checking, validation
save(prj); //call the method in DataService
// do postprocessing
}
}
//calling save
projectService.saveProjec(project, /*some args*/);
2nd
abstract class DataService {
public void save(Object data){
if(beforeSave(data)){
// persist the data
afterSave(data);
}
}
protected boolean beforeSave(){
return true;
}
protected void afterSave(){
}
}
//the service for Project objects
class ProjectService extends DataService {
public initSave(Object... args /*other save options*/ ){
// store these options in class properties
}
@Override
protected bool beforeSave(Project objectAboutToBeSaved){
// some preprocessing, checking, validation
// use class properties set by initSave if needed
return true;//if we want to continue with the saving procedure
}
@Override
protected bool afterSave(Project savedObject){
// do postprocessing
// use class properties set by initSave if needed
}
}
//calling save
projectService.initSave(/*some args*/);
projectService.save(project);
目前我们正在使用第一种模式,但我开始考虑转向第二种模式,因为:(
优点)
- 逻辑更好 跨多个对象类型的分离
- 统一方法命名(将允许创建通用单元测试:例如初始化每个对象及其服务并调用保存)
(缺点)
- 设置起来有点困难(initSave) - 甚至可能必须包括拆卸
方法我的想法来自CakePHP MVC框架,其中Model和Controller都包含了这样的回调方法,使用它我可以真正实现一些清晰的业务逻辑。
现在我正在 Java 中开发 - Spring + Spring Data Graph -(因此 javaish代码),但在我看来,这个问题可能是一个非常普遍的问题。
注意:给出的示例是保存过程,但删除过程也是如此。
I cannot decide between the following two patterns for eg. saving a dataObject (bean in my case). The two options are:
1st
abstract class DataService {
protected void save(Object data){
//persist the data
}
}
//the service for Project objects
class ProjectService extends DataService {
public void saveProject(Project prj, Object... args /*other save options*/ ){
// some preprocessing, checking, validation
save(prj); //call the method in DataService
// do postprocessing
}
}
//calling save
projectService.saveProjec(project, /*some args*/);
2nd
abstract class DataService {
public void save(Object data){
if(beforeSave(data)){
// persist the data
afterSave(data);
}
}
protected boolean beforeSave(){
return true;
}
protected void afterSave(){
}
}
//the service for Project objects
class ProjectService extends DataService {
public initSave(Object... args /*other save options*/ ){
// store these options in class properties
}
@Override
protected bool beforeSave(Project objectAboutToBeSaved){
// some preprocessing, checking, validation
// use class properties set by initSave if needed
return true;//if we want to continue with the saving procedure
}
@Override
protected bool afterSave(Project savedObject){
// do postprocessing
// use class properties set by initSave if needed
}
}
//calling save
projectService.initSave(/*some args*/);
projectService.save(project);
At the moment we are using the first pattern, but I began to think about moving to the second one, because:
(PROS)
- better logical separation
- unified method naming across multiple object types (would permit creation of generic unit tests: eg. initialize each object and its service and call save)
(CONS)
- bit harder to set up (initSave) - might even have to include a teardown method
The idea came to me from the CakePHP MVC framework, where both the Model and Controller included such callback methods, using which I could really implement some clear business logic.
Right now I'm developing in Java - Spring + Spring Data Graph -(thus the javaish code), but this question can be a quite generic one in my opinion.
Note: the example was given for save, but the same would be for the deletion process too.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
另一种解决方案是使用策略模式并执行如下操作。
我们使用这种方法进行预持久验证,有时甚至计算(基于其他字段)并设置要持久保存的数据对象的某些字段(例如,我们有一个基于其他字段更新的“完整”标志)每当持久化或更新我们的实体之一时的字段)。
您的策略:
您的数据服务:
然后像这样使用它们:
优点:
缺点
Another solution would be to use a strategy pattern and do something like the following.
We're using that approach to do pre-persist validation and sometime even calculate (based on other fields) and set some fields of the data object that is to be persisted (e.g. we have a "complete" flag that is updated based on other fields whenever the persist or update one of our entities).
Your strategy:
Your data service:
Then use them like this:
Pros:
Cons
我也不会说。对我来说,两者看起来都不必要地复杂。
一个简单的 CRUD 接口应该做的事情:
所有验证和检查都应该在到达持久层之前完成。我认为这违反了单一责任原则。
交易属于服务层。持久层无法知道它是否被要求参与事务。如果还有其他人怎么办?
你们的想法都过于复杂。我都会拒绝。
I'd say neither. Both look unnecessarily complex to me.
A simple CRUD interface ought to do:
All the validations and checks ought to have been done before you get to the persistence tier. It violates the single responsibility principle, in my opinion.
Transactions belong to the service tier. The persistence tier has no way to know if it's being asked to participate in a transaction. What if there are others as well?
Both your ideas are overly complex. I'd reject both.
我更喜欢第二个。
主要区别在于它告诉类的用户应该如何使用它。这是一个很大的优点(更明显)和一个小的缺点(灵活性较差)。另外,第二种方法允许更好地扩展子类(
ProjectService
的子类可以重用before()
方法并扩展after()
)。要记住的一件事是,子类实际上可以丢弃其中一个方法(通过覆盖它而不是在超类中调用它)。如果允许或不允许,请务必记录每个子类。I would prefer the second one.
The main difference is that it tells the user of the class, how it should be used. This is a big upside (more clear) and a small downside (less flexibility). Also the second method allows for better extension of the subclasses (a subclass of
ProjectService
can reuse thebefore()
method and extend theafter()
). One thing to keep in mind is that a subclass can actually discard one of the methods (by overriding it and not calling it in the super class). Be sure to document for each subclass if this is allowed or not.第一个示例更简单。如果您需要批量处理数据,第二个示例会更好。即开始/结束更新的开销很重要。
您仍然可以通过使用线程本地状态来使第二个示例线程安全。
您可以两全其美。
这可以用于两种模式。
这允许您混合和匹配并拥有一些执行单个更新的方法,但从某些方法调用时将隐式批处理保存的数据。
The first example is better for simplicity. The second example is better if you have a need to batch your data. i.e. the overhead of starting/ending an update is important.
You can still make the second example thread safe by using a thread local state.
You could have the best of both worlds with.
This could be used in two modes like this.
This allows you to mix and match and have some methods which perform a single update but when called from some methods will implicitly batch the saved data.