g.f*_*ley 6 domain-driven-design domain-model anemic-domain-model
我正在寻找一些关于我应该关注多少避免贫血领域模型的建议.我们刚刚开始使用DDD,并且正在努力解决有关简单设计决策的分析瘫痪问题.我们坚持在最新的点是一定的业务逻辑属于,比如我们有一个Order对象,它具有类似性质Status等.现在说我有像执行命令UndoLastStatus,因为别人犯了一个错误的命令,这不是那么简单因为只需更改Status其他信息就必须记录并更改属性.现在在现实世界中,这是一项纯粹的管理任务.所以我看到它的方式我有两个我能想到的选择:
选项1:将方法添加到订单中,以便类似Order.UndoLastStatus(),虽然这有点意义,它并不真正反映域.也是Order系统中的主要对象,如果涉及订单的所有内容都放在订单类中,事情就会失控.
选项2:创建一个Shop对象,并使用不同的服务代表不同的角色.所以,我可能有Shop.AdminService,Shop.DispatchService和Shop.InventoryService.所以在这种情况下,我会Shop.AdminService.UndoLastStatus(Order).
现在第二个选项我们有更多反映域的东西,并允许开发人员与业务专家讨论实际存在的类似角色.但它也走向了贫血的模式.一般来说哪种方式更好?
方案2肯定会导致程序性代码.
可能更容易开发,但更难维护.
现在在现实世界中,这是一项纯粹的管理任务
"管理"任务应该是私有的,并通过公共的,完全"域名"行动来调用.最好 - 仍然用易于理解的代码编写,这些代码是从域驱动的.
正如我所看到的那样 - 问题是UndoLastStatus域专家没什么意义.
他们更有可能在谈论制作,取消和填写订单.
这些方面的东西可能更合适:
class Order{
void CancelOrder(){
Status=Status.Canceled;
}
void FillOrder(){
if(Status==Status.Canceled)
throw Exception();
Status=Status.Filled;
}
static void Make(){
return new Order();
}
void Order(){
Status=Status.Pending;
}
}
Run Code Online (Sandbox Code Playgroud)
我个人不喜欢使用"状态",它们会自动共享给使用它们的所有内容 - 我认为这是不必要的耦合.
所以我会有这样的事情:
class Order{
void CancelOrder(){
IsCanceled=true;
}
void FillOrder(){
if(IsCanceled) throw Exception();
IsFilled=true;
}
static Order Make(){
return new Order();
}
void Order(){
IsPending=true;
}
}
Run Code Online (Sandbox Code Playgroud)
为了在订单状态发生变化时更改相关内容,最好的办法是使用所谓的域事件.
我的代码将沿着这些方向看:
class Order{
void CancelOrder(){
IsCanceled=true;
Raise(new Canceled(this));
}
//usage of nested classes for events is my homemade convention
class Canceled:Event<Order>{
void Canceled(Order order):base(order){}
}
}
class Customer{
private void BeHappy(){
Console.WriteLine("hooraay!");
}
//nb: nested class can see privates of Customer
class OnOrderCanceled:IEventHandler<Order.Canceled>{
void Handle(Order.Canceled e){
//caveat: this approach needs order->customer association
var order=e.Source;
order.Customer.BeHappy();
}
}
}
Run Code Online (Sandbox Code Playgroud)
如果秩序变得太大,你可能想要查看有限的上下文是什么(正如埃里克埃文斯所说 - 如果他有机会再次写下他的书,他会将有限的背景移到一开始).
简而言之 - 它是由域驱动的一种分解形式.
想法相对简单 - 从不同的视点(也称为上下文)获得多个订单是可以的.
例如 - 从购物上下文订购,从会计上下文订购.
namespace Shopping{
class Order{
//association with shopping cart
//might be vital for shopping but completely irrelevant for accounting
ShoppingCart Cart;
}
}
namespace Accounting{
class Order{
//something specific only to accounting
}
}
Run Code Online (Sandbox Code Playgroud)
但通常足够的域本身可以避免复杂性,如果你足够仔细地听它,它很容易分解.例如,您可能会听到OrderLifeCycle,OrderHistory,OrderDescription这样的专家术语,您可以利用这些术语作为分解的锚点.
注意:请记住 - 我对您的域名一无所知.
我正在使用的那些动词很可能对它完全陌生.
| 归档时间: |
|
| 查看次数: |
958 次 |
| 最近记录: |