重构访问遗留系统中存储库的域逻辑

wax*_*ing 7 java refactoring domain-driven-design repository

我正在使用具有贫血域模型的遗留系统.

域名具有以下实体classses: ,Car,CarType,.CarComponentCarComponentType

对于其中的每一个,都有一个单独的存储库.还有许多服务可以访问这些存储库并且基本上包含所有逻辑.

我需要实现一个方法来确定CarComponentType供应商是否可以停止使用.逻辑如下:只有当前没有现有汽车的组件才能停止组件.

最初,我在服务类中实现了它.

public boolean canBeDiscontinued(CarComponentType carComponentType) {
    List<Car> cars = carRepository.getCarsWithComponent(carComponentType);
    return cars.isEmpty();
}
Run Code Online (Sandbox Code Playgroud)

这有效 - 但是这个逻辑在代码中的其他几个地方使用.它可能会增长,它看起来像是适合类的东西CarComponentType:

public boolean canBeDiscontinued() {
    List<Car> cars = carRepository.getCarsWithComponent(this);
    return cars.isEmpty();   
}
Run Code Online (Sandbox Code Playgroud)

但是,我不能把它放在那里,因为它需要访问存储库(据我所知,它是一个非常严重的反模式,实体要知道数据访问层).加载组件类型时,我无法加载该类型的所有汽车,因为这可能是数千个对象.我们没有使用任何ORM,所以制作一个懒惰的加载集合不仅体积大,而且非常容易出错.

像我第一次在服务类中实际使用此方法更合适吗?这不重要吗?还有另一种选择吗?我应该从另一个起点开始重构吗?

还有一个类似的问题在这里.但是我的问题与Java有关,所以我不认为这个解决方案适用于我的情况.此外,提前抱歉使用汽车和组件作为我的域模型.:)

Mar*_*ann 5

Frederik Gheysels的回答很好,虽然可能有点短.详细说明:在您的情况下,您可以通过为您的规范定义一个接口(请原谅我的C#语法):

public interface ICarSpecification
{
    bool IsSatisfiedBy(CarComponentType carComponentType);
}
Run Code Online (Sandbox Code Playgroud)

然后,您可以创建使用您的存储库的ICarSpecification的implmenetation.像这样的东西:

public class CanDiscontinueSpecification : ICarSpecification
{
    private readonly CarRepository carRepository;

    public CanDiscontinueSpecification(CarRepository carRepository)
    {
         this.carRepository = carRepository;
    }

    public bool IsSatisfiedBy(CarComponentType carComponentType)
    {
        return this.carRepository.GetCarsWithComponent(carComponentType).Any();
    }
}
Run Code Online (Sandbox Code Playgroud)

你可以在那里停下来,但我对规格模式并不特别喜欢的是它不是很容易被发现.一种可能的解决方案是将规范注入CarComponentType本身:

public class CarComponentType
{
    private readonly ICarSpecification discontinueSpec;

    public CarComponentType(ICarSpecification discontinueSpec)
    {
        this.discontinueSpec = discontinueSpec;
    }

    public bool CanBeDiscontinued()
    {
        return this.discontinueSpec.IsSatisfiedBy(this);
    }
}
Run Code Online (Sandbox Code Playgroud)

或者,如果您不喜欢在类的每个实例中随身携带规范,则可以使用Method Injection而不是Constructor Injection:

public bool CanBeDiscontinued(ICarSpecification spec)
{
    return spec.IsSatisfiedBy(this);
}
Run Code Online (Sandbox Code Playgroud)

这种方法在实现方面并没有真正增加任何价值,但更容易被发现.

  • 好吧,它将您的类与存储库分离,通过传递执行您想要的测试的规范实现,可能更容易进行单元测试. (2认同)