'Inappropriate Intimacy in factory

My Factory has dependency on Repository. It calls many methods from Repository. Lets say something like this:

class CarFactory {
    private Repository repository;

    Car create() {
        detail = repository.findSomeDetail();
        if(detail.large()) {
          anotherDetail = repository.findAnotherDetail();
          return new Car(detail, anotherDetail);
        } else {
          anotherDetail = repository.findYetAnotherDetail();
          if(anotherDetail.expensive()) {
              cheapDetail = repository.findCheapDetail();
              return new SecondHandCar(cheapDetail);
          } else {
              smallDetail = repository.findSmallDetail();
              return new SmallCar(smallDetail);
          }
    }
}

It is hard to test, I need to mock lots of Repository methods. One problem is that Repository takes a lot of time to find something, so I can not find everything and then pick whatever I need. I need to call its methods only after certain criteria was met. Repository manages only single entity type, so I don't think it is a God Object. I tried to use Builder and ended up with:

class CarFactory {
    private Repository repository;
    private CarBuilder builder;

    Car create() {
        detail = repository.findSomeDetail();
        return builder.buildBasedOn(detail);
    }
}

However, it introduces new dependency in CarFactory and there is still problems inside Builder itself.



Solution 1:[1]

In my view, what can be done is creation of cache. You will preload all data from database. If there are many data, then preload only most recently used data. Take a look at LRU caching strategy. Read more about caching strategies.

If count of rows from database is not very big, you can create hashtables for each entity and it will be your cache. Then while creating an object, you can take your object from cache. It will be fast as gettting value from HashTable is O(1)

UPDATE:

If you want to have testable code, then you can use Dependency inversion Principle.

So you need to create interfaces of your dependencies and inject concrete objects to your factory.

Let me show an example. At first you need abstraction:

public interface ICarBuilder
{ 

}

Then implement interface in concrete type:

public class CarBuilder : ICarBuilder
{
}

And the next step is to introduce abstraction in your CarFactory:

class CarFactory
{
    private ICarBuilder _carBuilder;
    // other code is omitted for the brevity

    public CarFactory(ICarBuilder carBuilder) 
    {
        _carBuilder = carBuilder;
    }


    public Car create()
    {   
        return _carBuilder.buildBasedOn(detail);
        // other code is omitted for the brevity
    }
}

Then you can use like this:

CarFactory carFactory = new CarFactory(new CarBuilder());

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1