Domain driven design 聚合为服务

Domain driven design 聚合为服务,domain-driven-design,axon,Domain Driven Design,Axon,假设服务需要一些全局配置来处理某些请求 例如,当用户想做某件事时,它需要一些全局配置来检查用户是否被允许这样做 我意识到,在axon中,我可以使用命令处理程序来处理没有指定目标聚合的命令,因此处理部分没有问题 问题是,在试图更改配置时,我希望在上面有持久性存储和一些不变量。配置的整体思想是,它应该像轴突中的聚合一样一致 ConfigService { @Inject configRepository; @Inject eventGateway; @CommandHandler handle(c

假设服务需要一些全局配置来处理某些请求

例如,当用户想做某件事时,它需要一些全局配置来检查用户是否被允许这样做

我意识到,在axon中,我可以使用命令处理程序来处理没有指定目标聚合的命令,因此处理部分没有问题

问题是,在试图更改配置时,我希望在上面有持久性存储和一些不变量。配置的整体思想是,它应该像轴突中的聚合一样一致

ConfigService {
@Inject
configRepository;
@Inject
eventGateway;

@CommandHandler
handle(changeConfig){
let current = configRepository.loadCurrent;
//some checks

//persist here?
eventGateway.send(confgChanged)
}

@EventHandler
on(configChanged){
//or persist here?
configRepository.saveCurrent(configChanged.data)
}

}
如果我在命令处理程序上执行持久性,我认为我不应该使用事件处理程序,因为它会保存它两次。但是,当我不知何故丢失配置存储库数据时,我可以根据事件重建它

我不确定我在理解DDD概念的过程中遗漏了什么,简单地说,我想知道对于既不是聚合也不是实体的东西,在哪里放置命令处理程序。
也许我应该创建调用配置服务的命令处理程序,而不是将配置服务作为命令处理程序。

在我看来,您的全局配置要么是一个,要么是一组类似于中的规则

与中描述的模式不同,在DDD中,某些构建块/模式更通用,可以应用于您拥有的不同类型的对象

例如,实体是具有生命周期和身份的东西。生命周期中的阶段通常是:创建、持久化、从存储中重建、修改,然后通过删除、存档、完成等方式结束生命周期

值对象是没有标识的对象,(大多数情况下)是不可变的,两个实例可以通过其属性的相等性进行比较价值对象代表了我们领域中的重要概念,如:货币在处理会计、银行等的系统中,矢量3矩阵3在进行数学计算和模拟的系统中,如建模系统(3dsMax,Maya),视频游戏等。它们包含重要的行为

因此,您需要跟踪并具有标识的所有内容都可以是一个实体

您可以有一个规范作为一个实体,一个规则作为一个实体,一个事件如果有一个唯一的ID分配给它,也可以是一个实体。在这种情况下,您可以像对待任何其他实体一样对待它们。您可以形成聚合,拥有存储库和服务,并在必要时使用EventSourcing

另一方面,规范规则事件命令也可以是值对象

规范规则也可以是域服务

这里一个重要的东西也是有界上下文。更新这些规则的系统可能与应用这些规则的系统处于不同的有界上下文中。也有可能情况并非如此

这里有一个例子

让我们建立一个系统,客户可以在其中购买物品。该系统还将对具有特定规则的订单提供折扣

假设我们有这样一条规则:如果一个客户订购了超过5个行项目订单,他会得到折扣。如果该订单的总价格为某个金额(比如1000美元),他会得到折扣

销售团队可以更改折扣的百分比。销售系统具有可修改的订单计数策略聚合。另一方面,订购系统只读取OrderDicountPolicy集合,无法修改,因为这是销售团队的责任

销售系统订购系统可以是两个独立的限定上下文的一部分:销售订单订单范围上下文取决于销售范围上下文

注意:我将跳过大部分实现细节,只添加相关内容以缩短和简化此示例。如果它的意图不清楚,我将编辑并添加更多细节UUID折扣百分比货币是我将跳过的价值对象

公共接口OrderDiscountPolicy{
公共UUID getID();
公共折扣百分比getDiscountPercentage();
公开作废更改折扣百分比(折扣百分比);
公共bool可享受折扣(订单);
}
公共类LineItemsCountOrderDiscountPolicy实现OrderDiscountPolicy{
public int getLineItemsCount(){}
公共无效changeLineItemsCount(整数计数){}
公共图书馆可申请折扣(订购){
退货订单.getLineItemScont()>此.getLineItemScont();
}
//接口实现中的其他内容
}
公共类PriceThresholdOrderDiscountPolicy实现OrderDiscountPolicy{
公共资金getPriceThreshold(){}
公共无效更改价格阈值(货币阈值){}
公共图书馆可申请折扣(订购){
退货订单.getTotalPriceWithoutDiscount()>this.getPriceThreshold();
}
//接口实现中的其他内容
}
公共类行项目{
公共UUID getOrderID(){}
公共UUID getProductID(){}
公共数量getQuantity{}
公共资金getProductPrice(){}
公共资金总价值(){
返回getProductPrice().multiply(getQuantity())
public interface OrderDiscountPolicy {

    public UUID getID();

    public DiscountPercentage getDiscountPercentage();
    public void changeDiscountPercentage(DiscountPercentage percentage);

    public bool canApplyDiscount(Order order);
}

public class LineItemsCountOrderDiscountPolicy implements OrderDiscountPolicy {

    public int getLineItemsCount() { }

    public void changeLineItemsCount(int count) { }

    public bool canApplyDiscount(Order order) { 
        return order.getLineItemsCount() > this.getLineItemsCount();
    }

    // other stuff from interface implementation
}

public class PriceThresholdOrderDiscountPolicy implements OrderDiscountPolicy {

    public Money getPriceThreshold() { }

    public void changePriceThreshold(Money threshold) { }

    public bool canApplyDiscount(Order order) { 
        return order.getTotalPriceWithoutDiscount() > this.getPriceThreshold();
    }

    // other stuff from interface implementation
}

public class LineItem {

    public UUID getOrderID() { }
    public UUID getProductID() { }
    public Quantity getQuantity { }
    public Money getProductPrice() { } 

    public Money getTotalPrice() {
        return getProductPrice().multiply(getQuantity());
    }
}

public enum OrderStatus { Pending, Placed, Approced, Rejected, Shipped, Finalized }

public class Order {

    private UUID mID;
    private OrderStatus mStatus;
    private List<LineItem> mLineItems;
    private DscountPercentage mDiscountPercentage;

    public UUID getID() { }
    public OrderStatus getStatus() { }
    public DscountPercentage getDiscountPercentage() { };

    public Money getTotalPriceWithoutDiscount() { 
        // return sum of all line items
    }

    public Money getTotalPrice() { 
        // return sum of all line items + discount percentage
    }

    public void changeStatus(OrderStatus newStatus) { }

    public List<LineItem> getLineItems() {
        return Collections.unmodifiableList(mLineItems);
    }

    public LineItem addLineItem(UUID productID, Quantity quantity, Money price) {
        LineItem item = new LineItem(this.getID(), productID, quantity, price);
        mLineItems.add(item);
        return item;
    }

    public void applyDiscount(DiscountPercentage discountPercentage) {
        mDiscountPercentage = discountPercentage;
    }
}

public class PlaceOrderCommandHandler {

    public void handle(PlaceOrderCommand cmd) {

        Order order = mOrderRepository.getByID(cmd.getOrderID());

        List<OrderDiscountPolicy> discountPolicies =
             mOrderDiscountPolicyRepository.getAll();

        for (OrderDiscountPolicy policy : discountPolicies) { 

            if (policy.canApplyDiscount(order)) {
                order.applyDiscount(policy.getDiscountPercentage());
            }
        }

        order.changeStatus(OrderStatus.Placed);

        mOrderRepository.save(order);
    }
}

public class ChangeOrderDiscountPolicyPercentageHandler {

    public void handle(ChangeOrderDiscountPolicyPercentage cmd) {

        OrderDiscountPolicy policy = 
            mOrderDiscountRepository.getByID(cmd.getPolicyID());

        policy.changePercentage(cmd.getDiscountPercentage());

        mOrderDiscountRepository.save(policy);
    }
}