DDD(九)--工廠

一、引言

在針對複雜領域進行建模時,聚合、實體和值對象之間的依賴關係可能會變得十分複雜。在某個對象中爲了確保其依賴對象的有效實例被建立,須要深刻了解對象實例化邏輯,咱們可能須要加載其餘相關對象,且可能爲了保持其餘對象的領域不變性增長了額外的業務邏輯,這樣即打破了領域的單一責任原則,又增長了領域的複雜性。java

那如何去建立複雜的領域對象呢?由於複雜的領域對象的生命週期可能須要協調才能進行建立。 這個時候,咱們就能夠引入建立類模式——工廠模式來幫忙,將對象的使用與建立分開,將對象的建立邏輯明確地封裝到工廠對象中去。設計模式


二、工廠模式

工廠模式(Factory Pattern)是 Java 中最經常使用的設計模式之一。這種類型的設計模式屬於建立型模式,它提供了一種建立對象的最佳方式。函數

在工廠模式中,咱們在建立對象時不會對客戶端暴露建立邏輯,而且是經過使用一個共同的接口來指向新建立的對象。設計

DDD中工廠的主要目標是隱藏對象的複雜建立邏輯;次要目標就是要清楚的表達對象實例化的意圖。 而工廠模式是計模式中的建立類模式之一。藉助工廠模式咱們能夠很好實現DDD中領域對象的建立。code

而針對工廠模式的實現主要有四種方式:對象

  • 簡單工廠:簡單實用,但違反開放封閉;
  • 工廠方法:開放封閉,單一產品;
  • 抽象工廠:開放封閉,多個產品;
  • 反射工廠:能夠最大限度的解耦。

這裏就很少贅述了。接口


三、封裝內部結構

當須要爲聚合添加元素時,咱們不能暴露聚合的結構。咱們以添加商品到購物車爲例,來說解如何一步一步的使用工廠模式。生命週期

通常來講,添加到購物車須要幾個步驟:ci

  1. 加載用戶購物車
  2. 加載商品
  3. 建立新的購物車子項

相關的應用層代碼以下:get

// ......
public void add (Long goodsId, Long cartId) {
	Cart cart = new Cart();
	Goods goods = new Goods();
	cart = cartService.findById(cartId);
	goods = goodsService.findById(goodsId);
	cart.getSeedCart().add(goods);
	// ......
}

在以上代碼中,應用服務須要了解如何建立Cart的詳細邏輯。而這不該該時應用服務的職責,應用服務的職責在於協調。咱們嘗試作如下改變來避免暴露聚合的內部結構。

public class AddGoodsToCart {
	// ......
	public void add (Long goodsId, Long cartId) {
		Cart cart = new Cart();
		Goods goods = new Goods();
		cart = cartService.findById(cartId);
		goods = goodsService.findById(goodsId);
		cart.Add(goods, cart);
	}
}
	

public class Cart {
	public void Add  (Goods goods, Cart cart) {
		cart.getSeedCart().add(goods);
		cartService.savecart()
	}
	// ......
}

以上代碼展現了Basket(購物車)對象提供一個Add方法,用來完成添加商品到購物車的業務邏輯,對應用服務隱藏了購物車如何存儲商品的細節。另外購物車聚合可以確保其內部集合的完整性,由於它能夠確保領域的不變性。經過這種方式,完成了職責的切換,如今的應用服務要簡單的多。 變動 然而,卻引入了一個新的問題。根據需求,它需求要依賴一個Special(特別需求)。獲取建立購物車子項依賴的稅率,這並不屬於購物車的職責。而按照上面的實現,購物車承擔了第二責任,由於它必須始終了解如何建立有效的購物車子項以及在哪裏去獲取有效的稅率。

爲了不購物車承擔額外的職責和隱藏購物車子項的內部結構。下面咱們引入一個工廠對象來封裝購物車子項的建立,包括獲取Special。

public class Cart {
	 public void Add  (Goods goods, Cart cart) {
	 	CartFactory(cart, goods);
	 }
// ......
    }

public class CartFactory {
	public static void CreateCartFrom (Cart cart, Goods goods) {
		Special special = specialService.ObtainTaxRateFor (cart.getId());
	return new Cart (special, product.Id, goods);
	}
}

引入工廠模式後,購物車的職責單一了,且隔離了來自購物車子項的變化,好比個需求變化時,或購物車子項須要其餘信息建立時,都不會影響到購物車的相關邏輯。


四、隱藏建立邏輯

考慮這樣的需求:訂單建立成功後,進行發貨處理時,要求根據訂單的商品和收件人信息選擇合適的快遞方式。好比默認發順豐,順豐沒法送達的選擇中國郵政。

根據這個需求,咱們能夠抽象出一個Kuaidi(快遞)對象用來封裝快遞信息,和一個Delivery(發貨)對象用來封裝發貨信息(貨物、收件人信息、快遞等)。建立Delivery的職責咱們能夠放到Order中去,但針對Order來講它並不知道要建立(選擇)哪種Kuaidi(快遞)。因此,咱們能夠建立一個KuaidiFactory工廠負責Kuaidi對象的建立。

當要建立的對象類型有多個選擇,且客戶端並不關心建立類型的選擇時,咱們能夠在領域層使用工廠中去定義邏輯去決定要建立對象的類型。

五、小結

對象建立不是一個領域的關注點,但它確實存在於應用程序的領域層中。經過使用工廠能夠有效的保證領域模型的乾淨整潔,以確保領域模型的對現實的準確表達。使用工廠具備如下好處:

  • 工廠將領域對象的使用和建立分離。
  • 經過使用工廠類,能夠隱藏建立複雜領域對象的業務邏輯。
  • 工廠類能夠根據調用者的須要,建立相應的領域對象。

然而,並非任何須要實例化對象的地方都要使用工廠。只有當用工廠比使用構造函數更有表現力時,或存在多個構造函數容易形成混淆時,或者對要建立對象所依賴的對象不關心時,才選用工廠進行對象的建立。

DDD工廠並沒有特殊的地方,與經典工廠設計是一致的。

相關文章
相關標籤/搜索