业务建模:上下文(场景)还是服务?


DCI的从角色职责和场景的角度来理解业务感觉不容易,问几个问题?

1、就我理解,上下文是其着承上启下的作用,每个业务过程的一系列行为都想象出一个特定的上下文,实践中是不是很困难?
2、所有的业务交互行为都要发生在一定上下文(场景)下?
3、如果要上下文的话,业务行为是在固定的一个上下文(场景)下,还是在多个上下文(场景)下?
(同一个行为可能会被不同模块所调用,其上下文是一样吗?)

4、就业务建模来讲,感觉“上下文(场景)”并没有比“服务”更具优势,否则增加了不少困扰?

(DDD的服务其本质就对一个或多个实体行为组合或分组,起着协调作用,调用是直接引用,在描述业务领域上,不是显得更自然一点?)

我个人认为:其实DCI的场景相当于DDD的应用层,DDD服务相当于DCI的交互,实体相当于数据模型。

DCI比应用层贡献是,认为实体不是直接在应用层实施服务,而是通过扮演的角色,这样解耦了实体和服务之间的直接耦合,而是让角色参与服务,在应用层实施。

可以说,DCI对DDD是一个有力的补充,如果说DDD比较着重实体内部自身,那么DCI则着重实体外部交互行为。

其实角色这个概念在DDD中也有隐含,比如聚合根实际是实体在充当维护组群的角色,就象一个人充当小组的组长一样。通过聚合根这个角色,与外部划分界限,保持成员内部一致性。

对象的行为分两种:一种是对内,一种是对外。

对内维持状态一致性,比如setXXX/getXXX就是对内的行为,很多人瞧不起它,甚至认为多余,但是它在复杂状态维护上有重要作用。
通过聚合根这个角色,其实已经规定了对象的内部行为。

对外行为就是互动,DCI中讲的I,与外部行为称为互动,也可以称为事件和消息,或者服务,这些概念中都涉及双方,两个对象以上。
通过DCI角色,其实已经规定了对象的外部行为。

通过DDD+DCI,我们在实施OO时基本没有空白点,OO发展到了非常成熟完善的地步。

2012-09-12 07:35 "@banq"的内容
DCI比应用层贡献是,认为实体不是直接在应用层实施服务,而是通过扮演的角色,这样解耦了实体和服务之间的直接耦合,而是让角色参与服务,在应用层实施。 ...

2012-09-12 07:35 "@banq"的内容

对外行为就是互动,DCI中讲的I,与外部行为称为互动,也可以称为事件和消息,或者服务,这些概念中都涉及双方,两个对象以上。


我不否认这种方法能实现,问题就在这里,不管内部方法还是外部方法放在实体上,是否一味这个方法的粒度就可大可小,实体方法粒度描述不受控制的话,在对行为理解上,会产生模另两可感觉。

不同模块调用相同的实体方法,上下文应该多个?角色应多个?
(提出这么多模式让人眼花,都是“分而治之”惹的“祸”)
[该贴被clonalman于2012-09-12 17:14修改过]

其实在你另外一个文章:业务建模:CQRS应用场景中谈到涉及“销售模块与库存模块、财务模块”等的协调调用这种情况,这种协调应该是DCI的I交互的意思。

根据我总结的场景 事件和状态模板,这里的交互可以用事件实现,所以,达到与你分析的一样结果。

如果我们之前有这种分而治之的方法和意识,是不是在开发设计这些系统时就能够使用,相反,等到系统完成后,再去重构,危险相当大,因为这不是几个小模式小技巧,是事关系统稳定性的大架构,相当于重新开发,如果是我小命可能陪上,呵呵。

呵呵,分层、分模块是人认识上的必然,完全同意,如果能实现机器自动编程,就不一定要“分而治之了”。

DCI的交互,应该更强调角色与系统的交互,我之前提到的应用场景,可能就没有角色了的概念了,服务行为比角色行为来讲会更加纯粹一点

1、bounded contexts are used to break down the problem domain.
2、services are used to break down the solution domain.

这两句相当深刻!

关于BoundedContext与Service让我想起了一个常见业务场景:


public class Order
{
public OrderStatus OrderStatus
{
get;
set;
}

public event EventHandler<OrderApprovedEventArgs> Approved;

public void Approve()
{
if (Approved != null)
{
Approved(this, new OrderApprovedEventArgs(this));
}
OrderStatus = OrderStatus.InProgress;
}
}

上面代码相当理想,属性、事件、方法全部都有!!!
大家都看得懂,就是订单审批,不管什么系统,涉及订单都应该会有订单审批功能,是简单审批、还是多人多部门进行评审?(问题域)

public class SalesContext: BoundedContext
{
//描述什么样的问题(什么样的场景做什么事情)
protected void OnOrderApproved(object sender, OrderApprovedEventArgs e)
{
//如何做
}
}

不同业务形态的差异性可以用BoundedContext来显示体现

(订单实例化时自动实现Order.Approved += SalesContext.OnOrderApproved)

 
public class SalesContext: BoundedContext
{
protected void OnOrderApproved(object sender, OrderApprovedEventArgs e)
{
//简单发一下文件
var mailSerice = this.Container.Resolve<IMailSerice>();
mailSerice.Send("Approved")
}
}

public class MailSerice: IMailSerice
{
public void Send(String msg){
....
}
}

要怎么实现或进行协作还得靠Service (解决域)
[该贴被clonalman于2013-02-26 23:16修改过]

2013-02-26 22:54 "@clonalman
"的内容
不同业务形态的差异性可以用BoundedContext来显示体现 ...

想法不错,不过感觉把Context当作模板来做了,我想可能因为语言的实现能力问题才使用模板,模板好像突出了共性,而context概念是有界的,有边界的,突出了区别。两者可以偶尔交叉使用。

今天刚刚看到infoQ关于Bounded context文章:Using the Domain Driven Design Bounded Context Concept to Shrink a Large Domain Model

通过引入有界上下文,可以分割一个大的领域模型,起到 “约束”或“聚焦”作用,中心思想也是强调separating分割:
By separating classes for different contexts, e.g. separating classes for customer care from classes for orders and shipping, and putting these classes into separate DbContexts, Julie splits a large context, containing all classes in an application into smaller and more focused contexts. This retains the same large underlying data model and database tables.
[该贴被banq于2013-02-28 15:23修改过]