2011-11-08 34 views
1

我無法在例如以下兩種模式之間做出決定。保存一個dataObject(在我的情況下是bean)。這兩個選項是:哪種設計模式更適合保存/刪除數據?爲什麼?

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*/); 

第二

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); 

在我們使用的是第一圖案的時刻,但我開始思考移動到第二個,因爲:

(PROS)

  • 更好的邏輯分隔
  • 統一的方法命名跨多個對象類型(將允許創建通用的單元測試:例如,初始化每個對象和它的服務,並調用保存)

(缺點)

  • 有點難以成立(initSave) - 甚至可能包括一個拆卸方法

的想法來自CakePHP MVC框架,其中模型和控制器都包含這樣的回調方法,使用它我可以真正實現一些清晰的業務邏輯。

現在我正在開發Java - Spring + Spring Data Graph - (因此javaish代碼),但這個問題可以是一個非常通用的在我看來。

注意:該示例僅用於保存,但刪除過程也是如此。

回答

3

另一種解決方案是使用策略模式並執行如下操作。 我們正在使用這種方法進行預持續驗證,有時甚至計算(基於其他字段)並設置要持久化的數據對象的某些字段(例如,我們有一個「完整」標誌,根據其他領域每當堅持或更新我們的實體之一)。

您的策略:

interface SaveStrategy<T> { 
    boolean beforeSave(T data); 
    void afterSave(T data); 
} 

class SomeFancyProjectSaveStrategy implements SaveStrategy<Project> { 

    public SomeFancyProjectSaveStrategy(/*parameters*/) { 
    } 

    public boolean beforeSave(Project data) { 
    //whatever you like 
    } 

    public void afterSave(Project data) { 
    //whatever you like 
    } 
} 

您的數據服務:

class DataService { 
    public <T> void save(T data, SaveStrategy<? super T> strategy){ 
    if(strategy.beforeSave(data)){ 
     // persist the data 
     strategy.afterSave(data); 
    } 
    } 
} 

然後使用它們像這樣:

SaveStrategy<Project> saveStrategy = new SomeFancyProjectSaveStrategy(someParameters); //could reuse that 
dataService.save(project, saveStrategy); //the service might even be shared for different data objects 

優點:

  • 保存前和保存後操作與持久化分開
  • 只要包含可重用數據(如驗證規則但不包含狀態),您就可以重用策略。
  • 您可以使用一般的DataService

缺點

  • 如果需要特殊保存的邏輯,你可能必須維持至少兩個類:戰略和特殊的數據服務
1

我寧願第二個。

主要區別在於它告訴用戶該類應該如何使用。這是一個很大的優勢(更清晰)和一個小的缺點(更少的靈活性)。第二種方法允許更好的擴展子類(ProjectService的子類可以重用before()方法並擴展after())。有一件事要記住,一個子類實際上可以放棄其中一種方法(通過重寫它而不是在超類中調用它)。如果允許或不允許,請確保爲每個子類創建文檔。

1

第一個例子更簡單。如果您需要批量處理數據,第二個例子會更好。即開始/結束更新的開銷很重要。

您仍然可以通過使用線程本地狀態來使第二個示例線程安全。

你可以兩全其美。

bool beforeSave(Project objectAboutToBeSaved); 
void saveProject(Project prj, Object... args /*other save options*/); 
bool afterSave(Project savedObject); 

這可以在兩種模式下使用。

void saveProject(Project prj, Object... args /*other save options*/) { 
    boolean inBatch = inBatch(prj); 
    if (!inBatch) beforeSave(prj); 

    saveProject0(prj, args); 

    if (!inBatch) afterSave(prj); 
} 

這使您可以混合和匹配,並有一定的方法,其中執行一個更新,但是從一些方法調用時會隱批量保存的數據。

1

我不會說。對我而言,這兩者看起來都不那麼複雜

一個簡單的CRUD接口應該做的:

public interface GenericRepository<K extends Serializable, T> { 
    Collection<T> find(); 
    T find(K id); 
    K save(T value); 
    void update(T value); 
    void delete(T value); 
} 

所有驗證和檢查,你應該得到的持久層之前已經完成。在我看來,這違反了單一責任原則。

交易屬於服務層。持久層無法知道它是否被要求參與交易。如果還有其他人呢?

你的想法都過於複雜。我會拒絕這兩個。

+0

在我的代碼中,我使用存儲庫來保存/刪除數據。第一個例子在'saveProject(...)'上有'@ Transactional'註釋,而'save(...)'和'ProjectService'上的第二個必須在''after-'和'beforeDelete'方法。 在這種情況下,你是否仍然有上述分歧? – Matyas

+0

是的,我喜歡。在我看來,你的存儲庫不應該知道交易。服務知道工作單位。 – duffymo

+0

同意,但文章中描述的類在服務層,並且它們使用存儲庫(在保存/刪除之內) - 因此名稱ProjectService(處理與項目數據對象相關的操作) – Matyas