2012-02-25 30 views
2

背景:帶DAO/VO的MVC - 控制器應與哪個DAO對話?

我有我希望有人也許能夠解決設計模式問題。我用PHP編程,但我相信DAO/VO在Java中很流行。

我一直在使用MVC很多年了。我設計了一個MVC購物,但是使用了程序編程。因此,最近我決定再次使用面向對象來開發購物車。

問題:

我面臨的問題是,我的產品類沒有意義的,有RetrieveAll()方法。 例如如果我列出了10個產品,那麼我將從哪個實例調用RetrieveAll()方法?我會有10個選擇。

解決方案:

因此,我發現DAO/VO圖案。 除非我沒有足夠的研究這種模式 - 我相信每個數據庫表必須有一個模型+ DAO。沒有模型或DAO應該知道另一組模型或DAO。因此被封裝。 該模式非常有意義,將數據庫層拉離模型。

但是,在購物車中,我的產品被分配了類別。 一個類別可以是電子,服裝等

有3個表: - 類別(PID,名稱) - 類別項目(IID,名) - 類別鏈接(PID,IID)

從MVC方法來看,它沒有意識到控制器應該與哪個DAO交談?

它應該是:

  • 控制器會談所有3個DAO的,然後將合適的數據結構返回查看?
  • 或者DAO應該與另一個(以某種方式)對話並將單個結構返回給Controller?

Please see here for example (image)

回答

1

我不知道你是什麼意思VO。它是價值對象嗎?

我是DDD(領域驅動設計)方法的巨大粉絲(雖然我不認爲我的自我是上師)。在DDD中,您有所謂的服務服務是對您的域進行操作並返回數據的操作。服務使用你的域數據封裝了操作。

而不是讓控制器做所有的領域邏輯,比如要檢索什麼項目,使用什麼樣的DAO等等(爲什麼控制器應該關心域呢?),它應該封裝在它自己的域內服務內部的DDD情況。

因此,例如,您要檢索「電子」類別的所有類別項目。 你可以寫一個控制器,它看起來像這樣(原諒我,如果代碼具有無效的語法,其例如着想):

public function showItemsByCategoryAction($categoryName) { 
    $categoryId = $categoryDAO->findByName($categoryName); 
    if(is_null($categoryId)) { 
    //@TODO error 
    } 

    $itemIds = $categoryLinkDAO->getItemsByCategoryId($categoryId); 
    if(empty($itemIds)) { 
    //@TODO show error to the user 
    } 

    $items = $categoryItemDAO->findManyItems($itemIds); 

    //@TODO parse, assign to view etc 
} 

這就引入了至少兩個問題:

  1. 控制器是FSUC(胖嘟嘟醜陋控制器)
  2. 該代碼是不可重複使用的。如果你想添加另一個表示層(比如開發人員的API,網站的移動版本等),你必須複製粘貼相同的代碼(期望視圖渲染的部分),最終你會來將封裝這些代碼的東西,這是服務的目的。

在服務層相同的控制器可能看起來像

public function showItemsByCategoryAction($categoryName) { 
    $service = new Item_CategoryName_Finder_Service(); 
    $items = $service->find($categoryName); 

    if(empty($items)){ 
    //@TODO show empty page result, redirect or whatever 
    } 

    $this->getView()->bind('items', $items); 
} 

控制器現在是乾淨的,小的,所有的域邏輯封裝,可以隨時隨地的代碼重用的服務中。

現在有人認爲,控制器應該對DAO一無所知,並且只通過使用服務與域進行通信,其他人表示可以從控制器調用DAO,沒有嚴格的規則,決定哪種更適合爲你。

我希望這可以幫助你! 祝你好運:)

+0

我覺得您服務時,考慮encompases域行動這不適合自然地在域對象中。我不認爲域服務應該返回數據,他們可能但這不是他們的目的。這是版本庫的處理數據庫訪問的責任 – MikeSW 2012-02-25 15:58:04

+0

@MikeSW是的,你可能是對的。但問題並不在於DDD,我只是將DDD的設計模式(服務)帶入問題的背景中。如果你想去適當的DDD,那麼存儲庫不應該知道任何有關數據庫的信息,並且應該使用DAO來訪問存儲。我還聽說某個地方最好不要將存儲庫,DOA等暴露給控制器,而是隻公開服務層,因此控制器使用不同的服務在域中創建/編輯/操縱/查找數據,並在轉用儲存庫,工廠等。 – 2012-02-25 16:05:06

+0

我有點不同意這裏。只有存儲庫應該以任何形式瞭解數據庫。關於服務,我認爲這些應用服務是應用服務,但在這種情況下,它們只是一個補充層,我的意思是我不認爲它們在這裏增加任何價值,所以控制器也執行應用服務的角色。 – MikeSW 2012-02-25 16:21:34

1

我不是DDD專家,但這是我的看法。這是存儲庫模板應用的情況。基本上,域不知道也不關心DAO或其他任何與持久性有關的東西。最多知道存儲庫接口(應該在基礎設施級別實現)。

控制器知道域和存儲庫。存儲庫封裝了與數據庫相關的所有內容,應用程序只知道存儲庫本身(事實上,應該注入實際實現的接口)。然後在存儲庫中有DAO,但你認爲合適。存儲庫只接收和發回應用​​程序/域對象,與數據庫接口實現沒有任何關係。

簡而言之,任何與數據庫相關的部分都是其中的一部分,它是存儲庫的實現細節。

+0

您只需在DAO上創建另一個級別(存儲庫),但問題依然存在。我應該使用什麼?一個調用其他存儲庫的特定存儲庫?或者依次調用每個存儲庫(請參閱我的答案中的DAO示例)?按命名類別查找所有項目是一個沒有實體和存儲庫可以提供的操作。爲了封裝和重用性,它應該被封裝成類似Service的東西。並不一定像DDD上下文中定義的Service一樣,你也可以將其稱爲Action或Command,它只是封裝常用操作的一些層。 – 2012-02-25 16:12:55

+0

存儲庫具有明確的目的:將持久性細節與應用程序的其餘部分分開。 DAO是實現細節。存儲庫接口根據應用程序使用情況而定,您可以說某種程度上存儲庫本身就是應用程序使用的一種服務。通過命名類別查找所有項目正是存儲庫的一種方法,它將使用必要的DAO來獲取這些結果。然後,存儲庫將持久化對象「轉換」爲應用程序對象(通常通過自動映射) – MikeSW 2012-02-25 16:26:10

+0

我同意您描述的存儲庫的角色。但讓我們澄清一下:存儲庫可以調用另一個存儲庫?什麼樣的倉庫應該實現'FindItemsByCategoryName','CategoryRepository'或'ItemsRepository'方法? – 2012-02-25 16:37:13

0

返回類型可以決定哪些DAO方法應該去哪個DAO類,因此這道應該控制談話時,應考慮:

實現一個DAO類每個數據實體更清潔,

CRUD操作應該進入Dao類, C-Create,R-Read,U-Update,D-刪除

讀取操作不像創建,更新,刪除,大部分時間讀操作有不同的口味當考慮他們返回什麼。

對於讀操作,返回類型可以決定哪些DAO方法應該去哪個DAO類

以下是一些業務實體和有道

Exchange -> ExchangeDao 
Company -> CompanyDao 
Stock -> StockDao 
相關問題