领域建模实现思考
“Javaeye论坛-领域建模”板块有很多讨论,不再引述,直接列举我的观点。
JavaEE中领域建模的困境包括:
1) 类膨胀。 需要职责理顺,分散和委托出去。
2) 无法摆脱Entity的Domain Service注入?
思路:
1. 目前的 Service 模式是一种组件化的,形式上是 OO 的,实质上是组件的,它能很好的解决现有问题。 但忽视了领域对象之前的天然关联性。
2. 领域模型特征: 普遍共识一般是Domain Object要求“ 数据 + 行为 ”的完整封装,对象实例的行为基于自己的数据,对象之间存在数据关联(Data Association)和行为关联(Behavior Association)。此外领域对象还能响应事件。
一个应用的领域对象依据其相互关联,可由一个根对象(Root Model) 导航获取到任何一个的Domain Object。
因此一个完整的领域模型可以抽象为:
Domain Model = Data + Association + Behavior + Event
3. 恰当平衡领域建模思想和实践的冲突。
第一个问题:如类膨胀,就是谈的很多的充血问题。随着系统发展,一个Domain Object要承担的Behavior增多,代码中的Method增多,导致文件庞大。 这更主要是一个实现阶段的问题,但不能不认真考虑。
解决充血肯定要反向思考,即给对象“放血”。将行为分散,实现角度需要增加Behavior类或接口,协同构建Domain Model。
Qi4j 框架基本实现了这一点,Domain Object设计和方法定义完全靠 Interface 和 Interface继承; 方法实现类为Mixin,只关注它要实现的Interface,子类为Composite模式,实现了很好的放血和分散。
如:
Domain Object 定义
方法实现
子类(应该说是接口)定义
但Qi4j 还有Concern等很多概念,看它的范例代码,感觉巨复杂,大量用了Annotation,不很喜欢。
3) 领域建模对使用者(程序员)要简单,友好。
现有框架太多的EJB,Service,DAO等框架要求的类,分层清晰,但导致代码增多,开发量和使用难度增加。当然,因为这种架构设计的清晰,规范性,在实践中获得了很大成功,功劳不可忽视。
新一代的开发框架,如果要面向“领域驱动设计”,需要将 Service,DAO,VO等概念进行融合,实现Data 和Behavior的重新聚合,而且Behavior不管它是原子性的CRUD,还是粗粒度的Business Method。
4) 类设计思路1:Behavior类继承 Data 类,这样使用者面对的是数据和Behavior统一的对象实例;
5) 类设计思路2:Domain Object恰当划分Sub Domain, 避免Behavior膨胀。
6) 类设计思路3:1关联的对象( order.customer ) 既有数据,又有Behavior,不存在什么问题,Hibernate等已经很好支持; 但N关联的对象( 如:user.orders ) 是一个集合(Collection)仍是以Data Model为中心;需要变为以“Behavior + Data Model”为中心,重点在Behavior;需要一个集合对Element成员有CRUD操作, 特别是更业务性的操作。
7) 跨环境( Context )问题。
一个Domain Object 在一个系统的不同子系统,不同领域有不同的Data Model和Behavior,因此对Domain Object需要按Context 进行关注。
一个基类如Person如果在不同Context有不同的表现,Manager,Employee,Sale,Clerk等,就需要按各自 Context 设计,而不能单线继承的设计。
思考的编程模型:
[参考资料]
1. Robbin domain model的延伸讨论 http://www.iteye.com/topic/57075
2. Taowen 贫血的Domain Model http://www.iteye.com/topic/191261
3. Taowen 再论领域模型的困境 http://www.iteye.com/topic/401223
4. Lifethinker 一个简单例子:贫血模型or领域模型 http://www.iteye.com/topic/283668
5. javaboy2006 基于DDD项目的设计总结 http://www.iteye.com/topic/351597
“Javaeye论坛-领域建模”板块有很多讨论,不再引述,直接列举我的观点。
JavaEE中领域建模的困境包括:
1) 类膨胀。 需要职责理顺,分散和委托出去。
2) 无法摆脱Entity的Domain Service注入?
思路:
1. 目前的 Service 模式是一种组件化的,形式上是 OO 的,实质上是组件的,它能很好的解决现有问题。 但忽视了领域对象之前的天然关联性。
2. 领域模型特征: 普遍共识一般是Domain Object要求“ 数据 + 行为 ”的完整封装,对象实例的行为基于自己的数据,对象之间存在数据关联(Data Association)和行为关联(Behavior Association)。此外领域对象还能响应事件。
一个应用的领域对象依据其相互关联,可由一个根对象(Root Model) 导航获取到任何一个的Domain Object。
因此一个完整的领域模型可以抽象为:
Domain Model = Data + Association + Behavior + Event
3. 恰当平衡领域建模思想和实践的冲突。
第一个问题:如类膨胀,就是谈的很多的充血问题。随着系统发展,一个Domain Object要承担的Behavior增多,代码中的Method增多,导致文件庞大。 这更主要是一个实现阶段的问题,但不能不认真考虑。
解决充血肯定要反向思考,即给对象“放血”。将行为分散,实现角度需要增加Behavior类或接口,协同构建Domain Model。
Qi4j 框架基本实现了这一点,Domain Object设计和方法定义完全靠 Interface 和 Interface继承; 方法实现类为Mixin,只关注它要实现的Interface,子类为Composite模式,实现了很好的放血和分散。
如:
Domain Object 定义
public interface Speaker
{
String sayHello();
}
方法实现
public class SpeakerMixin
implements Speaker
{
public String sayHello()
{
return "Hello, World!";
}
}
子类(应该说是接口)定义
@Mixins( SpeakerMixin.class )
public interface PoliticianComposite extends Composite, Speaker // +others
{
}
但Qi4j 还有Concern等很多概念,看它的范例代码,感觉巨复杂,大量用了Annotation,不很喜欢。
3) 领域建模对使用者(程序员)要简单,友好。
现有框架太多的EJB,Service,DAO等框架要求的类,分层清晰,但导致代码增多,开发量和使用难度增加。当然,因为这种架构设计的清晰,规范性,在实践中获得了很大成功,功劳不可忽视。
新一代的开发框架,如果要面向“领域驱动设计”,需要将 Service,DAO,VO等概念进行融合,实现Data 和Behavior的重新聚合,而且Behavior不管它是原子性的CRUD,还是粗粒度的Business Method。
4) 类设计思路1:Behavior类继承 Data 类,这样使用者面对的是数据和Behavior统一的对象实例;
5) 类设计思路2:Domain Object恰当划分Sub Domain, 避免Behavior膨胀。
6) 类设计思路3:1关联的对象( order.customer ) 既有数据,又有Behavior,不存在什么问题,Hibernate等已经很好支持; 但N关联的对象( 如:user.orders ) 是一个集合(Collection)仍是以Data Model为中心;需要变为以“Behavior + Data Model”为中心,重点在Behavior;需要一个集合对Element成员有CRUD操作, 特别是更业务性的操作。
7) 跨环境( Context )问题。
一个Domain Object 在一个系统的不同子系统,不同领域有不同的Data Model和Behavior,因此对Domain Object需要按Context 进行关注。
一个基类如Person如果在不同Context有不同的表现,Manager,Employee,Sale,Clerk等,就需要按各自 Context 设计,而不能单线继承的设计。
思考的编程模型:
Category extends CategoryDO {
void deleteProduct(String productId);
}
Category category = Categorys.find("sss");
category.getId();
category.deleteProduct("xxxx");
category.getProducts().delete("sss");
category.getProducts().add("ddddd");
category.getProducts().query("xxxx");
[参考资料]
1. Robbin domain model的延伸讨论 http://www.iteye.com/topic/57075
2. Taowen 贫血的Domain Model http://www.iteye.com/topic/191261
3. Taowen 再论领域模型的困境 http://www.iteye.com/topic/401223
4. Lifethinker 一个简单例子:贫血模型or领域模型 http://www.iteye.com/topic/283668
5. javaboy2006 基于DDD项目的设计总结 http://www.iteye.com/topic/351597