开发者

C# factory - is upcast a must?

Does the C# factory pattern require an upcast?

I want God in class library G to create a开发者_如何学运维n 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


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());


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


I think you could use dependence injection. Try with an Inversion Of Control (IoC) container like Unity 2, StructureMap, Or Castle of Windsor.


You're describing an abstract factory pattern, although the "child" factories (e.g. AdamFactory) normally have something in common so you'd expect them to produce something more like a common interface rather than just an object (see Davide's answer)

You're right to worry about the up-cast since that will tie Eve to the implementation of Adam which defeats the purpose of a factory (unless you're really using it as a builder).

Question is, why do you need the God class at all?


Well, if God is a persistence class library as you mentioned in comment, then it should not influence the class design of the rest of the system.

So, I wouldn't add unnecessary interfaces. It's Ok to return an object from deserializer and downcast afterwards (e.g. BinaryFormatter, XmlSerializer).

The better way would be to make your deserializer generic.


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?

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜