tags:

views:

230

answers:

7

Hi all,

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

A: 

If you don't want to do the type check and instantiate the appropriate classes the only other way I could think of would be reflection which would save you some lines when having multiple classes but would be more complicated to implement

To be honest I think doing it the way you are now is a completely valid factory implementation and can't really see why to change it.

Gergely Orosz
A: 

I don't think this is necessarily a bad thing. At some point you need to declare the type of object you are creating. By hiding the call to the constructor of your various derived classes the factory lets you have one single location where the concrete classes are known.

There are a number of ways you could do this - a set of if statements, a dictionary, an enterprisey xml config file - but ultimately you need some way of mapping a type parameter of int to a new instance of MyDerivedIntClass. It may not be pretty but at least you're only writing the code once.

Andrew Kennan
+7  A: 

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.

Stefan Steinegger
You beat me to it :pBut this is the proper way to go!
Stormenet
+3  A: 

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.

XXXXX
thanks a ton for all the replies. immense education gained here.The primary reason for going this route is this: i have a base class with an 'ID' property whose data type is determined at run time (string, int or long are the main ones handled). The factory class/method is to return a derived class with the approprite data type for the derived class' ID. this is why i think i can't go the route of having a non generic base class/interface.
OhGee
+1  A: 

I usually use a Dictionary<string,Type> for each of my factories, where I register each available implementation type that the factory can return (uhm.. see this for more info: Is a switch statement applicable in a factory method?

You could adapt this to your needs and keep a Dictionary<Type,Type> of all your derived classes.

 ...
 Factories.StaticDictionary.Add(typeof(int),typeof(MyDerivedIntClass));
 Factories.StaticDictionary.Add(typeof(string),typeof(MyDerivedStringClass));
 ...

(or have each of your derived classes add to this dictionary automatically)

Then your factory would be simply:

    public static class MyClassFactory
    {
        public static MyGenericBaseClass<T> CreateMyClass<T>()
        {
          Activator.CreateInstance(
          Factories.StaticDictionary[typeof(T)]);
        }

    }
Radu094
A: 

If you want to go further than some of the examples that others have posted, you should look at a dependency injection framework.

Richard Hein
A: 

thanks a ton for all the replies. immense education gained here.

The primary reason for going this route is this: i have a base class with an 'ID' property whose data type is determined at run time (string, int or long are the main ones handled). The factory class/method is to return a derived class with the approprite data type for the derived class' ID. this is why i think i can't go the route of having a non generic base class/interface.

found this idea about 30 mins ago which does this in the factory method:

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

        if (typeof(T) == typeof(string))        
        {            
            MyGenericBaseClass<string> typedDerived = new MyDerivedStringClass();
            return (MyGenericBaseClass<T>)(object)typedDerived;         
        }        
        // **********************************************    
    }
}

looks hacky, particularly with the double cast, but seems to work. what do y'all think particularly in terms of maintainability??

OhGee