Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generics and Factories

Tags:

c#

generics

I'm new to generics and have been trying to figure out how i can return an instance of a class whose base is generic from a factory. See sample code below. The issues are highlighted in factory class:

public abstract class MyGenericBaseClass<T>
{
    public string Foo()
    {...}
}

public sealed class MyDerivedIntClass : MyGenericBaseClass<int>
{

}

public sealed class MyDerivedStringClass : MyGenericBaseClass<string>
{

}

public static class MyClassFactory
{
    public static MyGenericBaseClass<T> CreateMyClass<T>()
    {
        // **********************************************
        if (typeof(T) == typeof(int))
        {
            return new MyDerivedIntClass();
        }

        if (typeof(T) == typeof(string))
        {
            return new MyDerivedStringClass();
        }
        // **********************************************
    }
}

How do i get around this??

Thanks a ton in advance

Ohgee

like image 625
OhGee Avatar asked Dec 18 '22 05:12

OhGee


2 Answers

In most of my generic classes, I put a non-generic interface on. Actually, I would implement something like this:

public interface INonGenericInterface
{
    string Foo();
}

public abstract class MyGenericBaseClass<T> : INonGenericInterface
{
    public string Foo()
    {...}
}

public static class MyClassFactory
{
    public static INonGenericInterface CreateMyDerivedIntClass()
    {
        return new MyDerivedIntClass();
    }

    public static INonGenericInterface CreateMyDerivedStringClass()
    {
        return new MyDerivedStringClass();
    }
}

This way, you clearly state which types can be created and still decouple the caller from the concrete types.

Of course, you don't necessarily need the non-generic interface for this scenario, but in reality, you'll most likely need it.

like image 84
Stefan Steinegger Avatar answered Dec 19 '22 20:12

Stefan Steinegger


First of all, it's not clear why you're creating classes derived from your generic class, rather than using the generic class directly. Nor is it clear why you need a factory rather than just instantiating whatever classes you need directly. These patterns are important and useful, often the only way to solve certain problems, but they're not requirements. You should have good reasons to implement them.

I'll assume, though, you do indeed have good reasons that you've elided for the sake of brevity.

The point of using the factory pattern is to have some piece of code instantiate the correct class without that code knowing the correct class. Note that in your example this separation is missing: whoever is calling MyClassFactory.CreateMyClass<T> () must know the correct class, since that code has to pass the type as a generic parameter, which determines the correct class. If I know enough to call CreateMyClass<int> (), then I know enough to call new MyDerivedIntClass ().

There are two primary ways of implementing the factory pattern: static functions and factory classes.

With both methods, you'll need an abstract base class or interface "underneath" the generics:

public interface IMyInterface
{
    string Foo ();
}

public abstract class MyGenericBaseClass<T> : IMyInterface
{
    // ...
    abstract /* or virtual */ string Foo ();
}

Using the static function, you'll need a delegate type defined somewhere (class scope omitted):

// note: I'm not sure this is the correct syntax, but I think I'm in the ballpark
delegate IMyInterface MyInterfaceFactory ();

and the classes can implement them to return the correct type.

public sealed class MyDerivedIntClass : MyGenericBaseClass<int>
{
    // ...
    static IMyInterface CreateObject () { return new MyDerivedIntClass (); }
}

public sealed class MyDerivedStringClass : MyGenericBaseClass<string>
{
    // ...
    static IMyInterface CreateObject () { return new MyDerivedStringClass (); }
}

You pass the static function to the function that instantiates the object:

// ... somewhere else in the code ...

// create a IMyInterface object using a factory method and do something with it
void Bar (MyInterfaceFactory factory)
{
    IMyInterface mySomething = factory ();
    string foo = mySomething.Foo ();
}

// ... somewhere else in the code ...
void FooBarAnInt ()
{
    Bar (MyDerivedIntClass.CreateObject);
}

The second method is to use factory classes:

public interface IMyInterfaceFactory
{
    IMyInterface CreateObject ();
}

public class MyDerivedIntFactory : IMyInterfaceFactory
{
    public IMyInterface CreateObject () { return new MyDerivedIntClass (); }
}

public class MyDerivedStringFactory : IMyInterfaceFactory
{
    public IMyInterface CreateObject () { return new MyDerivedStringClass (); }
}

// ... somewhere else ...

// create a IMyInterface object using a factory class and do something with it
void Bar (IMyInterfaceFactory factory)
{
    IMyInterface mySomething = factory.CreateObject ();
    string foo = mySomething.Foo ();
}

// ... somewhere else in the code ...
void FooBarAnInt ()
{
    Bar (new MyDerivedIntFactory ());
}

Note that you can (and probably should) also make the factory classes singletons, but that's a different problem. Also, you can use an abstract base class instead of an interface; you'll need to add abstract (or virtual) and override as required.

Fundamentally, someone, somewhere, somehow has to know the correct type of object to instantiate. The point of factory objects is not to abstract that knowledge away completely, but to separate the knowledge of what type of object to create from the code that actually creates the object. If you don't need that separation, the factory pattern is not particularly useful.

like image 36
XXXXX Avatar answered Dec 19 '22 19:12

XXXXX