Creating a single factory for unrelated objects

Solution for Creating a single factory for unrelated objects
is Given Below:

I have several classes that are not related to each other.

public class Apple
{
    
}

public class Giraffe
{
    
}

I can create a separate factory for each but I want to get a structure like below.

Factory<Apple>.CreateSingle();

I want to produce a single apple with the code above. Also with the following code;

Factory<Giraffe>.CreateCollection(20);

I want to get 20 giraffes.

To do this, I created an IFactory generic interface.

public interface IFactory<out T>
{
    T CreateSingle();
    IEnumerable<T> CreateCollection(int count);
}

And a factory for each type;

public class AppleFactory : IFactory<Apple>
{
    public Apple CreateSingle() =>
        new()
        {
           //some code
        };

    public IEnumerable<Apple> CreateCollection(int count)
    {
          // CreateSingle X count times, add to collection and return
    }
}

public class GiraffeFactory: IFactory<Giraffe>
{
    public Giraffe CreateSingle() =>
        new()
        {
           //some code
        };

    public IEnumerable<Giraffe> CreateCollection(int count)
    {
          // CreateSingle X count times, add to collection and return
    }
}

The main factory looks like this;

public static class Factory<T>
{
    private static IFactory<T> GetFactory()
    {
        if (typeof(T) == typeof(Apple)) return (IFactory<T>) new AppleFactory();
        if (typeof(T) == typeof(Giraffe)) return (IFactory<T>) new GiraffeFactory();
        return null;
    }
    public static T CreateSingle() => GetFactory().CreateSingle();
    public static IEnumerable<T> CreateCollection(int count) => GetFactory().CreateCollection(count);


}

The if structure here looks pretty ugly. Is there a way I can do what I want to do in a cleaner way? These days, I am trying to learn design patterns and I force myself to use design patterns. The code may seem unnecessarily cluttered for this reason. It’s totally experimental.

[UPDATE]

Actually I made up apples and giraffes to represent database objects (Orders, Customers etc). During unit testing, I sometimes needed mocks of these objects. For this reason, I coded a factory for each object type. Afterwards, I thought if I could gather these factories in a single factory. I also checked the Abstract factory method, but it didn’t quite fit.

I made some changes to the code. Generating objects singularly has a separate structure for each object (because its properties are different). But after making a single production, producing a collection is the same for all of them. For this reason, I moved the collection production method to the main factory.

Also, I used reflection to select the appropriate factory to produce within the main factory.

Again, I did all this for experimental purposes only. I didn’t get any useful results. I think it’s best to use separate factories anyway.

public static class Factory<T>
{
    private static IFactory<T> _factory;
    private static IFactory<T> SetFactory()
    {
        var type = typeof(IFactory<T>);
        var desiredFactory = AppDomain.CurrentDomain.GetAssemblies()
            .SelectMany(s => s.GetTypes())
            .First(p => type.IsAssignableFrom(p));
        if (_factory == null || desiredFactory != _factory.GetType())
        {
            _factory=(IFactory<T>)Activator.CreateInstance(desiredFactory);
        }
        return _factory;
    }
    public static T CreateSingle() => SetFactory().CreateSingle();

    public static IEnumerable<T> CreateEnumerable(int count)
    {
       // I removed creating collection method from each factory to here
    }

This can be implemented using Suppliers and method references to create some clean code. You can make some modifications to make use of the create() method instead of the method reference to constructor if you need. I have kept it simple here.

abstract class Animal<T> implements Supplier<Animal> {
}

public abstract class Fruit<T> implements Supplier {
}

public class Giraffe<T> extends Animal{
    @Override
    public Giraffe get(){
        System.out.println("Create Giraffe");
        return new Giraffe();
    }
}


public class Apple extends Fruit{
    @Override
    public Apple get(){
        System.out.println("Create Apple");
        return new Apple();
    }
}


public abstract class AbstractFactory<T>{
    abstract T createEntity(String action);
}


class AnimalFactory<T extends Animal> extends AbstractFactory<T>{

    private  final Map<String, Supplier<T>> map =
            Map.of(
                    "Giraffe", new Giraffe()
//                    "Lion", Lion::new
            );
    @Override
    T createEntity(String action){
        System.out.println("Return Animal Factory");
        return (T) map.get(action);
     }
}

class FruitFactory<T extends Fruit> extends AbstractFactory<T>{

    private final Map<String, Supplier<T>> map =
            Map.of(
                    "Apple", new Apple()
//                    "Orange", Orange::new
            );
    @Override
    T createEntity(String action){
        System.out.println("Return Fruit Factory");
        return (T) map.get(action);
    }
}


public class TestFactory {
    public static void main(String[] args) {
        AnimalFactory<Giraffe> animalFactory = new AnimalFactory<>();
        Animal giraffe = animalFactory.createEntity("Giraffe");
        System.out.println("Created giraffe::" + giraffe);

        FruitFactory<Apple> fruitFactory = new FruitFactory<>();
        Apple apple = fruitFactory.createEntity("Apple");
        System.out.println("Created apple::" + apple);

    }
}

//ouput
Return Animal Factory
Created giraffe::[email protected]
Return Fruit Factory
Created apple::[email protected]