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.
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