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

时间:2009-08-12 08:31:52

标签: java refactoring repository domain-driven-design

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

该域具有以下实体类:CarCarTypeCarComponentCarComponentType

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

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

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

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

这有效 - 但是这个逻辑在代码中的其他几个地方使用。它可能会增长,而且它看起来像 in CarComponentType类,而不是:

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

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

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

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

4 个答案:

答案 0 :(得分:5)

Frederik Gheysels的回答很好,虽然可能有点短。详细说明:在你的情况下,你可以通过为你的规范定义一个接口来开始(借口我的C#语法):

public interface ICarSpecification
{
    bool IsSatisfiedBy(CarComponentType carComponentType);
}

然后,您可以创建使用您的存储库的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();
    }
}

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

public class CarComponentType
{
    private readonly ICarSpecification discontinueSpec;

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

    public bool CanBeDiscontinued()
    {
        return this.discontinueSpec.IsSatisfiedBy(this);
    }
}

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

public bool CanBeDiscontinued(ICarSpecification spec)
{
    return spec.IsSatisfiedBy(this);
}

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

答案 1 :(得分:3)

这听起来像是Specification pattern

的好候选人

答案 2 :(得分:3)

我不认为“这可以停止”属于任何一类。谁负责确定零件是否可以停产?不是汽车或汽车组件。我认为您在服务中实施初始方法时走在正确的轨道上。也许你需要一个CarInventoryManagementService来负责回答有关汽车库存项目的问题,如:

carsUsingComponent( CarComponent comp )
canComponentBeDiscontinued( CarComponent comp )
etc

如果代码中有多个位置需要询问与库存相关的问题,例如您的“canBeDiscontinued”,那么创建一个具有该职责的服务可能是有意义的。

答案 3 :(得分:1)

我认为我不像下一个男人那样厌恶贫血领域模型,这并不是轻描淡写。

然而,鉴于您正在研究的系统已经建立了贫血领域模型/服务(反)模式,我认为引入其他模式可能会在孤立的情况下完成系统的威慑,我相信您已经在这里。这样的决定应该由团队做出,并且应该有明显的好处。

另外,恕我直言,我认为您的原始代码片段比其他答案中提出的解决方案更简单(没有冒犯Mark和Frederik,只是观察:-)而且更复杂的解决方案并没有真正带来任何好处 - 我意思是,两种情况下的功能相同,但后者使用更多的移动部件

就如何进行而言,只举一个例子,很难说。介绍一个ORM(你提到当前没有使用)可能是一种方法,因为它应该减少你的服务类中的代码,并有明显的好处,所以我很想从那里开始,然后一旦到位审查情况。

相关问题