Alex Rivera | Logout

C# factory - is upcast a must?

Asked 2011-02-02T08:41:50.183
18

Does the C# factory pattern require an upcast?

I want God in class library G to create an Adam in class library A without making G dependant on A. God produces Adams for consumption by Eve in class library E, and it's OK for Eve to know and depend on Adam. (edit - this sample keeps getting better and better :)

The solution I could think of is having an AdamFactory in A. This way AdamFactory knows Adam and can easily create it (possibly by just calling Adam's constructor). God receives an AdamFactory and can order it to CreateAdam.

Now, because God isn't allowed to know Adam, AdamFacotry's CreateAdam must return an object, and this requires Eve to up-cast the object returned by AdamFactory to an Adam.

This will work, I think. However, I feel uneasy about up-casting as it's a no-no. Is this really a must?

P.S. - No Blasphemy intended, and I apologize if someone's feelings were hurt. It seemed better to use God and Adam instead of Creator and Created because the two latter words are too similar to each other.

Edit: Re interfaces suggestion. Let's assume Adam has two methods: ProvideLove, ProvideFood and ProvideProtection (we're keeping this sample kis-safe :). Eve uses Adam for these two purposes, but of course God doesn't. So why provide God with the knowledge that AdamFactor returns something that implements an IAdam and not just an object? I don't get it!

Edit: The working code (with everybody in the same library, which my goal is to separate to different libraries) looks something like this:

Adam God.LoadAdam(AdamID theAdamID)
       var adam = new Adam(theAdamId, this)

Adam.Adam(AdamID theAdamID, God theGod)
      _god = theGod
      _mind  = theGod.LoadMind(theAdamId, this)

Mind God.LoadMind (AdamID theAdamID, Adam theAdam)
      var mind  = new Mind (theAdam)
      var mindId = new minId(theAdamId)
      mind.DeserializeFromFile(minId)

Mind.Mind (Adam theAdam)
      _adam = theAdam

                    
                    
                    
Edit
Report

3 Answers

9

I am not sure I completely understand the requirements but here is a suggestion:


//in assembly G
public abstract class HumanFactory<T>
{
    public abstract T CreateHuman();
}

//in assembly A
public class Adam { }
//in assembly A
public class AdamFactory : HumanFactory<Adam>
{
    public override Adam CreateHuman()
    {
        return new Adam();
    }
}

//in assembly G
public class God
{
    public T Create<T>(HumanFactory<T> factory)
    {
        return factory.CreateHuman();
    }
}

and the usage:


//Somewhere in assembly E
Adam adam = new God().Create(new AdamFactory());
answered 2011-02-02T09:00:04.790
1

What about using interfaces so God knows IAdam, or something like IHuman ?

answered 2011-02-02T08:44:33.420
0

OK, what about sprinkling in some generics here?

Let's say God may accept Factories of any type T that adhere to the following interface:

interface IFactory  {
  Type CreatedType { get; }
  object Create();
}

An abstract class to implement this may look like this:

abstract class AbstractFactory<T> : IFactory {
  public Type CreatedType { get { return typeof(T); }
  public virtual object Create() {
    return innerCreate();
  }
  protected abstract override T innerCreate();
}

Now, you can register factories with God:

God.RegisterFactory(new AdamFactory());

AdamFactory inherits from AbstractFactory<Adam>

God stores its factories in a dictionary where the key is the type returned by the IFactory interface

the Create Method now looks like that:

God.Create<Adam>();

God looks into its factories, sees there is one for typeof(T) of the generic method, retrieves the factory, calls create and downcasts to T.

What do you think?

answered 2011-02-02T09:45:09.017

Your Answer