首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >依赖于存储库的DDD Validator规范

依赖于存储库的DDD Validator规范
EN

Software Engineering用户
提问于 2020-10-13 08:33:46
回答 3查看 1.2K关注 0票数 1

我读过这个https://stackoverflow.com/questions/5818898/where-to-put-global-rules-validation-in-ddd,并创建了我的验证器。

但是现在我需要创建一个验证器,它必须检查订单实体。

这就是问题所在:当我创建或编辑实体"Car“时,我需要检查两个条件:

如果有10辆或更多的实体车,我不能拥有带有值“红色”的属性颜色=“红色”。如果实体"Warehouse“中没有带有"FF0000”项代码的条目,则属性颜色不能包含值" Red“--我需要使用ICarRepository来计数属性红色,使用IWarehouseRepostiory来检查是否有代码"FF0000”的项。

代码语言:javascript
运行
复制
public class CarValidator : IValidator<Car>
{
    public CarValidator(ICarRepository carRepository, IWahrehouseRepository wahrehouseRepository)
{
.....
}

    private readonly IList<ISpecification<Car>> Rules =
        new List<ISpecification<Car>>
            {
                new AvaiableRedColorSpecification(carRepository, wahrehouseRepository),
            };

    public bool IsValid(Car entity)
    {
        return BrokenRules(entity).Count() > 0;
    }

    public IEnumerable<string> BrokenRules(Car entity)
    {
        return Rules.Where(rule => !rule.IsSatisfiedBy(entity))
                    .Select(rule => GetMessageForBrokenRule(rule));
    }
}

public class AvaiableRedColorSpecification : ISpecification<Car>
{
    public bool IsSatisfiedBy(ICarRepository carRepository, IWahrehouseRepository wahrehouseRepository)
    {
        return carRepository.CountRedColor() < 10 &&
                wahrehouseRepository.HaveItemCode("FF0000");

    }
}

注入我的依赖的最佳方法是什么,因为通过这种方式,我需要在Car实体中为Add/Edit注入存储库,我认为在实体中注入存储库不是一个好主意

读取AL响应后的编辑实现

我已经决定使用验证模式,所以我创建了一个

代码语言:javascript
运行
复制
interface IRuleSpecification<T>
{
    Task<ValidatorResult> IsSatisfiedAsync(T subject);
}
interface IValidator<T, TResult>
{
    Task ExecuteCheckAsync(T entity, TResult validateObject);
    bool IsValid { get; }
    IEnumerable<ValidatorResult> BrokenRules { get; }
    TResult ValidateObject { get; }
}

public static async Task<IValidator<CarDto, CarEntity>> FactoryCreator(CarDto dto, IEnumerable<IRuleSpecification<CarDto>> rules)
{ ... }

在这种情况下,每当我尝试创建实体汽车时,我都必须在具有调用工厂的响应性的类中传递IRuleSpecification (在我的例子中,使用我称为CarCreatorCommand的CQRS )。

CarCreatorCommand通过依赖注入提高IRuleSpecification列表。

IRuleSpecification的实现类已经注入了IRepository以重新表示颜色的列表。这样,验证器就有了IReposiory的依赖性。

EN

回答 3

Software Engineering用户

发布于 2020-10-13 09:02:27

当您将存储库或其他依赖项注入域时,域变得不那么纯净了。不纯域模型很难进行测试和推理。因此,纯域模型是首选。

那么,在不注入存储库的情况下,如何才能满足以下两个条件呢?

如果有10辆或更多的实体车,我不能拥有带有值“红色”的属性颜色=“红色”。如果实体"Warehouse“没有带有项目代码"FF0000”的条目,则属性颜色不能具有值"Red“。

Car实体可以有一个将所需信息作为参数的方法或构造函数,而不是从存储库中获取它。例如:

代码语言:javascript
运行
复制
public static Car Create(Model model, Engine engine, Color desiredColor, IReadOnlyList<ColorCount> usedColors, IReadOnlyList<Color> availableColors)
{
   // do validation on usedColors and availableColors
   return new Car(model, engine, desiredColor);
}

在从应用程序服务调用此方法之前,从存储库中获取信息。usedColors集合包含使用每种颜色的次数,availableColors集合包含仓库中的所有颜色。

这样,所有决策都可以在域中进行,而不需要任何进程外的依赖关系.

票数 1
EN

Software Engineering用户

发布于 2020-10-14 19:30:45

这里少了点什么。实际的规则是什么?

当然,显而易见的答案是,您可以为任何Car创建一个Color。你就是不能用它做任何事!你想用你的Car干什么?也就是说,这个系统的行为是什么?

我们是在尝试Assemble他们吗?然后呢?Store

代码语言:javascript
运行
复制
class CarFactory 
{ 
    public CarFactory(List<Model> models, List<Engine> engines, List<Color> colors)
     
    public Car Assemble(CarSpec spec)
    {
        //validate specification against available components
    }
}

// VO
class CarSpec
{
    public readonly Model model

    public readonly Engine engine

    public readonly Color color
}

class CarWarehouse
{
    public CarWarehouse(List<Car> cars)

    // alternatively
    public CarWarehouse(Dictionary<Color, int> numberOfEachColor)

    public InventoryTicket Store(Car car)
    {
        //validate the Car's current color against inventory
    }
}

现在我们可以推测出这样的用例:

代码语言:javascript
运行
复制
// Manufacture Car Handler

var spec = new CarSpec(cmd.Model, cmd.Engine, cmd.Color)

var car = factory.Assemble(spec) // may throw

var ticket = warehouse.Store(car) // may throw

repo.Save(car, ticket)

重要的是,上面提到的不是数据,而是我们系统的行为。我们并不担心通用的“规范”或“规则”,也不担心是否有任何“有效”。我们只是在嵌入域逻辑..。好吧..。直接进入域名!这样更简单。每个不变量都是在其应用的相同上下文中强制执行的。也就是说,在与其相关的行为单位内。

我们不关心Car的组件,直到我们想要对Car做些什么。这就是业务流程的工作方式:“如果Car不符合某些标准,我们就无法制造(组装和存储)它。”DDD寻求提供的基本视角(实际上是OOP)是,行为需要与数据放在一起,而不是围绕数据。

不验证数据,验证流程。

这样,Validator<Car>就真正地代表了DDD的对立面。我们选择关注数据(Car)而不是行为。我们不仅仅是在验证一个Car,我们还在某些上下文中验证一个Car。这是什么背景?我看不出你领域里有这些话。有东西不见了..。

票数 1
EN

Software Engineering用户

发布于 2020-10-13 12:13:11

显然,领域有一个“规则”的概念。这些规则超越了Car实体,但是定义了什么是有效的仓库。

假设需求会增加,并且解决方案应该支持多个仓库。在这种情况下,每个仓库应该支持一套不同的规则(取决于仓库的大小、文化问题、.)。

因此,这些规则的验证与仓库的addCar函数相关联。汽车不应该为其他汽车而烦恼。实体不应该为它们所处的集合而烦恼。

您所面临的问题是该设计缺陷的直接后果。

我可以想象用例应该限制仓库中汽车的可用颜色的数量;如果是这样的话,规则应该是仓库的一个可访问属性:wareHouse.availableCarColors

票数 0
EN
页面原文内容由Software Engineering提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://softwareengineering.stackexchange.com/questions/417857

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档