1
\$\begingroup\$

I'm facing the problem of needing to instantiate lots of cars, and I'd like to recycle the cars no longer used.

Each one of my car types, which define how each car should be created, are treated as singletons and there will never be two instances of the same type. I could program this in the example, but lets just assume that they are perfectly managed to only ever have one instance.

Each Car Type is both the definition of how to create the car and also the factory / dispenser for creating new Car instances with that type.

To explain more on why I wish each type to be it's own 'Dispenser', is for the recycling aspect. I expect to be creating lots of cars and also recycling them, so I'd like to keep GC to a minimum. So each type which was already created to the type's requirements can be recycled when it's done being used. Of course I'll be sanitizing the car when it's recycled (Remove the pieces of doritos from inbetween the seats etc').

So there can be one Toyota factory, which is passed to any number of Toyota Car Types. These in turn define the different specifications for the Toyota Car.

The types are essentially taking over the responsibility of customizing the car based on the type once it is out of the factory

You may ask, what's the purpose of the factories in this design, since I could just call new ToyotaCar without using a factory at all.

I wanted to keep the factories since they can be used to track / manage ALL cars of a certain type.

Like for example if I wanted to have the MazdaFactory display a list of all the cars that were created in it and break a random one's breaks.

Does this design break SOLID principles?

Am I overthinking and there's a much simpler approach?


public interface IDispenser<T>
{
    T Dispense();

    void Recycle(T t);
}

public class Car{

}

public abstract class CarFactory<T> where T : Car, new()
{
    public abstract T newCar();
}

public class DefaultCarFactory<T> : CarFactory<T> where T : Car, new()
{
    public override T newCar(){
        return new T();
    }
}

public abstract class CarType<T> : IDispenser<T> where T : Car, new()
{
    protected CarFactory<T> carFactory;

    protected Queue<T> recycledCars;

    // Each car type has to have a country origin
    public String countryOrigin = null;

    public CarType()
    {
        carFactory = new DefaultCarFactory<T>();
        recycledCars = new Queue<T>();
    }

    public CarType(CarFactory<T> carFactory)
    {
        this.carFactory = carFactory;
        recycledCars = new Queue<T>();
    }

    public abstract T Dispense();
    public abstract void Recycle(T t);
}


// Toyota

public class ToyotaCar : Car{}

public class ToyotaCarFactory : CarFactory<ToyotaCar>
{
    public override ToyotaCar newCar()
    {
        return new ToyotaCar();
    }
}

public class ToyotaCarType : CarType<ToyotaCar>
{

    public String toyotaOrnamentMaterial;

    public ToyotaCarType(ToyotaCarFactory toyotaCarFactory, String countryOrigin) : base(toyotaCarFactory)
    {
        this.countryOrigin = countryOrigin;
    }

    public override ToyotaCar Dispense()
    {
        if (recycledCars.Count > 0)
            return recycledCars.Dequeue();

        ToyotaCar newToyotaCar = carFactory.newCar();

        // newToyotaCar.create hood ornament from the material

        return newToyotaCar;
    }

    public override void Recycle(ToyotaCar toyotaCar)
    {
        recycledCars.Enqueue(toyotaCar);
    }
}

// Mazda

public class MazdaCar : Car{}

public class MazdaCarFactory : CarFactory<MazdaCar>
{
    public override MazdaCar newCar()
    {
        return new MazdaCar();
    }
}

public class MazdaCarType : CarType<MazdaCar>
{
    public MazdaCarType(MazdaCarFactory mazdaCarFactory, String countryOrigin) : base(mazdaCarFactory)
    {
        this.countryOrigin = countryOrigin;
    }

    public override MazdaCar Dispense()
    {
        return carFactory.newCar();
    }

    public override void Recycle(MazdaCar mazdaCar)
    {
        recycledCars.Enqueue(mazdaCar);
    }
}

public class VariableWheeledMazdaCarType : MazdaCarType
{
    public int numberOfWheels = 0;

    public VariableWheeledMazdaCarType(MazdaCarFactory mazdaCarFactory, String countryOrigin, int numberOfWheels) : base(mazdaCarFactory, countryOrigin)
    {
        this.numberOfWheels = numberOfWheels;
    }

    public override MazdaCar Dispense()
    {
        if (recycledCars.Count > 0)
            return recycledCars.Dequeue();

        MazdaCar newMazdaCar = carFactory.newCar();

        // Set specific behaviour based on the number of wheels
        // newMazdaCar.turnRadius = w/e

        return newMazdaCar;
    }
}

// A default factory made car, if some type doesn't want to specify a factory that creates it.

public class DefaultMazdaCarType : CarType<MazdaCar>
{
    public override MazdaCar Dispense()
    {
        if (recycledCars.Count > 0)
            return recycledCars.Dequeue();

        MazdaCar newCar = carFactory.newCar();

        return newCar;
    }

    public override void Recycle(MazdaCar mazdaCar)
    {
        recycledCars.Enqueue(mazdaCar);
    }
}

public class main
{

    public static T InstantiateFromType<T>(CarType<T> carType) where T : Car, new()
    {
        T car = carType.Dispense();

        return car;
    }

    public static void Main()
    {
        // Mazda

        MazdaCarFactory mazdaCarFactory = new MazdaCarFactory();

        VariableWheeledMazdaCarType threeWheeledMazdaCarType = new VariableWheeledMazdaCarType(mazdaCarFactory, "Japan", 3);

        // Create a three wheeled mazda car
        MazdaCar threeWheeledMazdaCar = InstantiateFromType<MazdaCar>(threeWheeledMazdaCarType);

        MazdaCarType mazdaCarType = new MazdaCarType(mazdaCarFactory, "Japan");

        // Create a default mazda car
        MazdaCar defaultMazdaCar = InstantiateFromType<MazdaCar>(mazdaCarType);



        // Toyota

        ToyotaCarFactory toyotaCarFactory = new ToyotaCarFactory();

        ToyotaCarType toyotaCarType = new ToyotaCarType(toyotaCarFactory, "Japan");

        // Create a default toyota car
        ToyotaCar defaultToyotaCar = InstantiateFromType<ToyotaCar>(toyotaCarType);

        ToyotaCar anotherDefaultToyotaCar = toyotaCarType.Dispense();

        // Create a car that uses the default factory

        DefaultMazdaCarType defaultFactoryCarType = new DefaultMazdaCarType();

        MazdaCar defaultFactoryMade = defaultFactoryCarType.Dispense();
    }   
}

```
\$\endgroup\$
  • \$\begingroup\$ I think I'll end up going for something a bit simpler which will be mix in object pools in a factory pattern. \$\endgroup\$ – g3trans Oct 29 at 18:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.