在针对复杂领域进行建模时,聚合、实体和值对象之间的依赖关系可能会变得十分复杂。在某个对象中为了确保其依赖对象的有效实例被建立,须要深刻了解对象实例化逻辑,咱们可能须要加载其余相关对象,且可能为了保持其余对象的领域不变性增长了额外的业务逻辑,这样即打破了领域的单一责任原则,又增长了领域的复杂性。java
那如何去建立复杂的领域对象呢?由于复杂的领域对象的生命周期可能须要协调才能进行建立。 这个时候,咱们就能够引入建立类模式——工厂模式来帮忙,将对象的使用与建立分开,将对象的建立逻辑明确地封装到工厂对象中去。设计模式
工厂模式(Factory Pattern)是 Java 中最经常使用的设计模式之一。这种类型的设计模式属于建立型模式,它提供了一种建立对象的最佳方式。函数
在工厂模式中,咱们在建立对象时不会对客户端暴露建立逻辑,而且是经过使用一个共同的接口来指向新建立的对象。设计
DDD中工厂的主要目标是隐藏对象的复杂建立逻辑;次要目标就是要清楚的表达对象实例化的意图。 而工厂模式是计模式中的建立类模式之一。借助工厂模式咱们能够很好实现DDD中领域对象的建立。code
而针对工厂模式的实现主要有四种方式:对象
这里就很少赘述了。接口
当须要为聚合添加元素时,咱们不能暴露聚合的结构。咱们以添加商品到购物车为例,来说解如何一步一步的使用工厂模式。生命周期
通常来讲,添加到购物车须要几个步骤:ci
相关的应用层代码以下: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工厂并没有特殊的地方,与经典工厂设计是一致的。