gpt4 book ai didi

domain-driven-design - 领域驱动设计 : Avoiding anemic domains and modelling real world roles

转载 作者:行者123 更新时间:2023-12-04 15:03:31 26 4
gpt4 key购买 nike

我正在寻找一些关于我应该在多大程度上关注避免贫血域模型的建议。我们刚刚开始使用 DDD,并且正在与简单设计决策的分析瘫痪作斗争。我们坚持的最新一点是某些业务逻辑所属的位置,例如我们有一个 Order对象,具有 Status 等属性等等。现在说我必须执行像 UndoLastStatus 这样的命令因为有人把订单弄错了,这不是仅仅改变Status那么简单。因为必须记录其他信息并更改属性。现在在现实世界中,这是一项纯粹的管理任务。所以我看到它的方式有两个我能想到的选择:

  • 选项 1:添加要订购的方法,例如 Order.UndoLastStatus() ,虽然这有点道理,但它并不能真正反射(reflect)领域。还有Order是系统中的主要对象,如果涉及订单的所有内容都放在订单类中,事情可能会失控。
  • 选项 2:创建 Shop对象,并且具有代表不同角色的不同服务。所以我可能有Shop.AdminService , Shop.DispatchService , 和 Shop.InventoryService .所以在这种情况下,我会有 Shop.AdminService.UndoLastStatus(Order) .

  • 现在第二个选项我们有了更多反射(reflect)领域的东西,并且允许开发人员与业务专家讨论实际存在的类似角色。但它也走向了贫血模型。一般来说,哪种方式更好?

    最佳答案

    选项 2 肯定会导致程序代码。
    可能更容易开发,但更难维护。

    Now in the real world this is a pure administration task



    “管理”任务应该是私有(private)的,并通过公共(public)的、完全“域的”操作调用。最好 - 仍然用易于理解的代码编写,这些代码是从域驱动的。

    正如我所看到的 - 问题是 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;
    }
    }

    我个人不喜欢使用“状态”,它们会自动共享给所有使用它们的东西——我认为这是 unnecessary coupling .

    所以我会有这样的事情:
    class Order{
    void CancelOrder(){
    IsCanceled=true;
    }
    void FillOrder(){
    if(IsCanceled) throw Exception();
    IsFilled=true;
    }
    static Order Make(){
    return new Order();
    }
    void Order(){
    IsPending=true;
    }
    }

    为了在订单状态发生变化时更改相关内容,最好的办法是使用所谓的 domain events .
    我的代码看起来像这样:
    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();
    }
    }
    }

    如果订单增长太大,您可能想查看 bounded contexts是(正如 Eric Evans 所说——如果他有机会再次写他的书,他会将有界上下文移到开头)。

    简而言之 - 它是一种由域驱动的分解形式。

    想法相对简单 - 从不同的观点(即上下文)拥有多个订单是可以的。

    例如。 - 从购物上下文订购,从会计上下文订购。
    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
    }
    }

    但是通常足够多的域本身可以避免复杂性,并且如果您足够仔细地听它,它很容易分解。例如。您可能会从专家那里听到诸如 OrderLifeCycle、OrderHistory、OrderDescription 之类的术语,您可以利用这些术语作为分解的 anchor 。

    注意:请记住 - 我对您的域的了解为零。
    我使用的那些动词很可能对它完全陌生。

    关于domain-driven-design - 领域驱动设计 : Avoiding anemic domains and modelling real world roles,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6824032/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com