Java – Refactoring domain logic that accesses repositories in a legacy system

domain-driven-designjavarefactoringrepository

I am working with a legacy system that has an anemic domain model.

The domain has the following entity classses: Car, CarType, CarComponent, CarComponentType.

For each of these, there is a separate repository. There is also a number of services that access these repositories and contain basically all logic.

I need to implement a method that determines if a CarComponentType can be discontinued by the vendor. The logic is as follows: a component can be discontinued only if there are no existing cars with that component today.

Initially, I implemented this in a service class.

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

This works – but this logic is used from several other places in the code. It might grow, and it looks like something that could fit inside the CarComponentType class instead:

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

However, I can't put it there, since it needs to access the repository (and as I understand it is a very serious antipattern for entities to be aware of the data access layer). When loading a component type I can't load all cars of that type since that could be thousands of objects. We are not using any ORM, so making a lazy loaded collection for not only be bulky but also very error-prone.

Is it more appropriate to actually have this method in a service class as I first did? Is it not important? Is there another alternative? Should I start refactoring from another starting point?

There is a similar question here. But my question relates to Java, so I don't think that solution is applicable in my case. Also, sorry in advance for using cars and components as my domain model. 🙂

Best Answer

Frederik Gheysels answer is good, although perhaps a bit short. To elaborate: In your case, you could start out by defininig an interface for your specification (excuse my C# syntax):

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

You can then create an implmenetation of ICarSpecification that uses your Repository. Something like this:

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();
    }
}

You could stop right there, but the thing I don't particularly like about the Specification pattern is that it is not very discoverable. One possible solution would be to inject the Specification into the CarComponentType itself:

public class CarComponentType
{
    private readonly ICarSpecification discontinueSpec;

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

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

Alternatively, if you don't like to carry around the Specification in every instance of the class, you could use Method Injection instead of Constructor Injection:

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

Such a method doesn't really add any value in terms of implementation, but is more discoverable.

Related Topic