2014-02-05 93 views
1

我繼承了使用JPA來訪問數據庫的用Java編寫的應用程序。該應用程序使用了我之前沒有遇到過的設計模式,並且我真的會對使用此模式的原因進行一些指導。像許多應用程序一樣,我們有一個前端,中間件和後端數據庫。數據庫通過DAO訪問。 DAO上的每個方法加載一個實體DTO,它只是一個POJO,只有getter和setter,然後該實體DTO被傳入一個實體,它具有改變實體狀態的其他方法。一個例子[類名稱變更爲保護inocent]每個實體的DTO對象

enum Gender 
{ 
    Male, 
    Female 
} 

class PersonDTO 
{ 
    private String mFirstName; 
    private String mLastName; 
    private Gender mGender; 
    ... 

    String getFirstName() { return this.mFirstName; } 
    String setFirstName(String name) { this.mFirstName = name; } 
    // etc 
} 

class Person 
{ 
    PersonDTO mDTO; 
    Person(PersonDTO dto) 
    { 
     mDTO = dto; 
    } 

    String getFirstName() { return mDTO.getFirstName() } 
    String setFirstName(String name) { mDTO.setFirstName(name); } 
    // and so on 

    void marry(Person aNotherPerson) 
    { 
     if(this.getGender()==Gender.Female && 
       aNotherPerson.getGender()==Gender.Male) 
     { 
      this.setLastName(aNotherPerson.getLastName()); 
     } 
     aNotherPerson.marry(this); 
    } 
} 

這是在全國30個左右的實體類重複,倍增至60與DTO的,我只是不能讓我的身邊,爲什麼頭。我理解有關分離收斂的(比特),我也理解(比特)基於EAO的設計與基於活動記錄的設計之間的區別。

但它真的要走這麼遠嗎?是否至少應該有一個「DB」對象,它只包含映射到數據庫字段的getter和setter?

回答

1

聲明:在這個問題上有不同的意見,根據您的系統架構,您可能沒有選擇。

有了這個說法......我見過這個模式實現之前,不是它的一個巨大的粉絲,在我看來是重複大量的代碼,沒有增加任何實際價值。在使用XML API的系統(如SOAP)中,它似乎特別受歡迎,因爲它可能很難將XML結構直接映射到對象結構。在你的特定情況下,它似乎更糟,因爲在重複的getFirstName()/ getLastName()方法之上,業務邏輯(屬於服務層)編碼到pojo中(它應該是一個簡單的數據傳輸對象像DTO)。 pojo爲什麼要知道只有異性的人才能結婚?

爲了更好地理解爲什麼,你能解釋一下這些DTOs的來源嗎?是否有前端將數據提交給控制器,然後將控制器轉換爲DTO,然後用於使用數據填充實體 - 正確的數據?

+0

由於Web服務調用都是由定時器運行的一個類處理的,因此DTO被創建。它會關閉,調用Web服務,填充DTO,持久化它們,然後創建存儲在內存中的「實體」。然後前端訪問實體並通過控制器對它們進行變異。至於「pojo爲什麼要知道只有異性的人才能結婚?」 (21世紀不好的例子!) - 不是OOP的一個核心部分嗎?所以你可以說有一個CelebrityPerson覆蓋了marry(),並且不需要他們的配偶名稱嗎?Vs是你的服務層類型的一個開關,方式? –

+0

@詹姆斯霍布森 - 問題是爲什麼人處理結婚?還有離婚方法嗎?如何通過電子郵件讓人們知道離婚已經最終確定(現在您的Person類知道電子郵件了)?添加新功能時,方法列表可以變得無限長。這就是爲什麼應該有MarriageService來處理結婚和離婚操作,所以POJO不必知道它被使用的每個場景。分離關注將是這裏的指導性OOP負責人。至於處理不同的婚姻類型,請查看策略模式。 – SergeyB

+0

@JamesHobson - 我想它歸結爲Person類,在一個典型的N層應用程序中可疑地看起來很像服務。考慮寫一個單元測試。如果Person是一個沒有getFirstName()/ getLastName()的服務,那麼你只需測試marry(Person person1,Person person2)。但是在這個設置中,你必須測試你的setter和getters。 – SergeyB

0

這似乎不是已知的模式。

一般而言

  • 常見的是保持一個單獨的對象以表示在數據庫中的記錄,被稱爲域對象。
  • 對象上的CRUD操作是DAO類的一部分,其他業務操作將成爲Manager類的一部分,但這些類都不會將該域對象存儲爲成員變量,即DAO和Manager都不帶狀態。它們只是處理作爲參數傳入的域對象的元素。
  • DTO用於前端和後端之間的通信以呈現來自DB的數據或接受來自最終用戶的輸入
  • DTO通過Manager類轉換爲Domain對象,其中執行驗證和修改每個商業規則。使用DAO類將這些域對象保存在數據庫中。
+0

缺乏「經理」類是我認爲是什麼令我困惑。你會說這樣做會更像是:PersonManager.marrayPeople(Person person1,Person person2)等,而不是這些實體內的操作? –

+0

這就對了@JamesHobson,結婚方法應該是經理類的一部分。 – Vikdor

1

也可能是因爲它們只是用來將JPA註釋與富域對象分開。

所以我猜測有人不喜歡在一個類中有JPA註釋和豐富的域對象行爲。有人可能會認爲JPA註釋和富域對象不應該在同一層(因爲註釋混合了關注點),所以如果你贏得了這個論證,你會得到這種分離。

另一個你會看到這種事情發生的地方是當你想從富域對象中抽象類似的註釋(比如web服務中的jaxb註解)。

所以意圖可能是DTO作爲從代碼到數據庫的序列化機制,這與here by martin fowler提到的意圖非常相似。

+0

謝謝 - 得到它爲什麼我在「didn」 t喜歡在一個類中使用JPA批註和豐富的域對象行爲「 –

0

我曾參與過一個項目,我們擁有DTO,目的只是將信息從前端控制器傳輸到某個外觀層。然後,Facade層負責將這些DTO轉換爲域對象。

此分層背後的想法是從域中分離前端(視圖)。有時DTO可以包含多個域對象以實現聚合視圖。但是,域層始終提供乾淨,可重用,可緩存(如果需要)的對象。