如何在领域驱动设计中管理聚合以避免过度耦合?

huangapple go评论76阅读模式
英文:

How to manage aggregates in DDD to not be too coupled?

问题

我想知道一种(或多种)不会过多耦合我的聚合的方法,这里有一个具体的解释。

例如,我有一个订单,里面不能超过100个商品

所以我创建了一个类似于以下的聚合:

Order {
    List<Item> Items { get; private set; }

    private int _maxItemCapacity = 100;

    public Item AddItem(string itemName) {
        if (Items.Count + 1 > _maxItemCapacity) 
        {
            throw new Exception("You have reached the maximum limit of items");
        }
        var item = new Item(itemName);
        Items.Add(item);
        return item;
    }

    public Item GetItem(Guid itemId) {
        var item = Items.Where(item => item.Id == itemId).First();
        return item;
    }
}
Item {
    public Guid Id { get; private set; }

    public string Name { get; private set; }

    public Item(string name) {
        Id = Guid.NewGuid();
        Name = name;
    }
}

所以现在当我想要向我的订单中添加一些商品时,我将通过我的不变式,这很完美,但是...

如果我想要通过商品ID获取我的订单中的某个商品,首先我需要获取我的订单和它所有的商品,然后再找到我的特定商品。

如果我有1000个或更多的商品,我不想在每次获取订单时都获取所有这些商品,我只想在添加商品时通过验证(不变式)。

我如何才能在订单中拥有这些验证,而不必将所有商品都放在里面?(我不想在应用层中拥有这些验证)。

英文:

I want to know a way (or ways) to not couple too much my aggregate, there's a concrete explication.

For example i have an order that can not have more than 100 items inside.

So i create an aggregate like

Order {
    List<Item> Items { get; private set; }

    private int _maxItemCapacity = 100;

    public Item AddItem(string itemName) {
        if (Items.Count + 1 > _maxItemCapacity) 
        {
            throw new Exception("You have reached the maximum limit of items");
        }
    var item = new Item(itemName);
    Items.Add(item);
    return item;
  }

    public Item GetItem(Guid itemId) {
        var item = Items.Where(item => item.Id == itemId).First();
        return item;
    }
}
Item {
    public Guid Id { get; private set; }

    public string Name { get; private set; }

    public Item(string name) {
        Id = Guid.NewGuid();
        Name = name;
    }
}

So now when i want to add some item to my Order i will pass through my invariant and that's perfect but...

If i want to get like only 1 of these items inside of my order by item Id, first i need to get my order with all he's items and after find my specific item.

And what if i had like 1000 items or more, i don't want to get all these items with my order, i want to pass through my validation (invariant) when i add some but without getting all items every time with the order.

How could i have an order with these validations without all items inside? (I don't want to have these validations in Application Layer).

答案1

得分: 1

请不要忘记,聚合对象优化了写操作,而不是读操作。因此,如果你只需要读取特定数据而不打算在特定操作中更改它,那么完全可以绕过聚合对象,以最有效的方式从数据存储中读取。

例如,如果你只需要获取特定订单项的数据以在用户界面上显示它,那么只需从数据存储中读取数据。

另一方面,如果你还需要将项目写入聚合对象作为单独的事务,而不需要这个聚合对象来确保所有项目的一致性,那么你可以考虑将这些项目拆分为单独的聚合对象,并在当前聚合对象中通过ID引用它们。

英文:

Please don't forget that aggregates are optimized for writes, not for reads. So if you just need to read specific data you are not planning to change within that specific action it is totally fine to bypass the aggregate and read from your data storage in whatever way is most efficient for reading.

For instance, if just need to get the data of a specific order item to display it on your user Interface than just read the data from your data store.

If you, on the other hand also need to write to items inside your aggregate as a separate transaction where this aggregate is not needed to guarantee the consistency across all items, then you could think of splitting these items out as separate aggregates and reference those by id in your current aggregate.

huangapple
  • 本文由 发表于 2023年7月27日 23:07:34
  • 转载请务必保留本文链接:https://go.coder-hub.com/76781113.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定