C#n派生对象的通用工厂模式(创建所有超类型)?

时间:2011-07-24 08:09:39

标签: c#

我有一个带有工厂方法的通用对象工厂FactoryBase<T>

public abstract class FactoryBase<T> where T : new()
{
    public virtual T CreateInstance()
    {
        T thing = new T();

        // Tweak 'thing' a bit...

        return thing;
    }
}

这对于创建各种类型的混凝土工厂非常有用:

public class FruitFactory : FactoryBase<Fruit>
{
    public override Fruit CreateInstance()
    {
        Fruit fruit = base.CreateInstance();

        // Do some Fruit polishing stuff...

        return fruit;
    }
}

但是,如果我想创建一个派生自Fruit的工厂类型:

,则模式会中断

第一次尝试:(工作,但不正确)

在这里,AppleFactory直接继承了FactoryBase<Apple> - 这是错误的,因为AppleFactory应该依靠FruitFactory来构建一个精美的Fruit来构建我们的Apple

// Should inherit FruitFactory, not FactoryBase
public class AppleFactory : FactoryBase<Apple>
{
    public override Apple CreateInstance()
    {
        Apple apple = base.CreateInstance();

        // FruitFactory is left out above, so...
        // ...we have to do all the Fruit polishing stuff...
        // ... and any apple stuff...

        return apple;
    }
}

第二次尝试:(完全失败)

继承FruitFactory显然是一个错误,因为它是非通用的并且返回Fruit而不是Apple

// COMPILE ERRORS
public class AppleFactory : FruitFactory
{
    public override Apple CreateInstance()  // ERROR: Override method must return Fruit
    {
        Apple apple = base.CreateInstance(); // ERROR: FruitFactory returns a Fruit
        return apple;
    }
}

“丑陋”的解决方案?

通过将FruitFactory重构为通用FruitFactory<T>,我可以创建一个正确派生的AppleFactory

public abstract class FruitFactory<T> where T : Fruit, new()
{
    public override T CreateInstance()
    {
        T fruit = (T)base.CreateInstance();

        // Do some Fruit polishing stuff...

        return fruit;
    }
}

// AppleFactory that property calls FruitFactory<Apple>
public class AppleFactory : FruitFactory<Apple>
{
    public override Apple CreateInstance()
    {
        Apple apple = base.CreateInstance();

        // ... ONLY apple stuff needed!!!

        return apple;
    }
}

我故意使FruitFactory<T>抽象,因为客户端代码调用FruitFactory<Fruit>似乎很难看和冗余。因此,我提供了一个非通用的FruitFactory,它不需要任何主体来完全发挥作用:

// Concrete FruitFactory
public class FruitFactory : FruitFactory<Fruit> { }

投诉:

每当我需要一个更多派生类型的工厂时,我必须将相应的基本类型的工厂转换为抽象通用。

换句话说,如果我有FooFactory我必须将其转换为FooFactory<T>才能创建DerivedFooFactory : FooFactory<DerivedFoo>

同时,我必须制作一个新的具体FooFactory : FooFactory<Foo>

或者......我可以直接通用工厂:

var fruitFactory = new FruitFactory<Fruit>(); // Double-Fruity! sigh...

是否有更简洁的方法来创建AppleFactory,首先从Apple中获取FruitFactory而不需要继承链中每个'中间人'类型的泛型类?

注意:我真的不想使用反射或复杂的方案。

2 个答案:

答案 0 :(得分:4)

我仍然无法关注您的问题,但我认为它可以通过使FruitFactory<T>非抽象来解决:

public class FruitFactory<T> : FactoryBase<T> where T : Fruit, new()
{        
    // I'm assuming this is in FactoryBase<T>
    public override T CreateInstance()
    {
        return new T();
    }
}

然后您可以从中派生并在撰写CreateInstance时覆盖AppleFactory

答案 1 :(得分:0)

我正在努力解决类似的问题,我们有一个继承层次结构,它使用带参数的构造函数,并且需要在创建时“抛光”。 问题是我们无法重用较少派生工厂的“抛光”代码,因为它与“新”语句(不是无参数构造函数)相结合。

我认为我们找到的解决方案可能对其他因为类似问题而产生问题的人有用(但它仍然具有泛型冗余):

// Abstract factory class that handles the method calls
public abstract class AbstractFactory<TDto, TObject> : IFactory<TDto, TObject>
{
    /// <summary>
    /// Create and initialize the object using data from Dto
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    public TObject Create(TDto dto)
    {
        TObject obj = CreateInstance(dto);
        Initialize(dto, obj);
        return obj;
    }

    /// <summary>
    /// Create a new instance of the object
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    protected abstract TObject CreateInstance(TDto dto);

    /// <summary>
    /// Initialize the instance of the object (the "polishing")
    /// </summary>
    /// <param name="dto"></param>
    /// <param name="objeto"></param>
    protected abstract void Initialize(TDto dto, TObject objeto);
}

// The Fruit is abstract, so is the factory. It don't override the abstract method that will have the "new" statement, just the "polishing" stuff.
public abstract class FruitFactory<TFuitDto, TFruit> : AbstractFactory<TFruitDto, TFruit>
    where TFruitDto : FruitDto
    where TFruit : Fruit
{
    protected override void Initialize(TFruitDto dto, TFruit objeto)
    {
       // Do the fruit "polishing" here
    }
}

public class AppleFactory<TAppleDto, TApple> : AbstractFactory<TAppleDto, TApple>
    where TAppleDto : AppleDto
    where TApple : Apple
{
    protected override TApple CreateInstance(TAppleDto dto)
    {
       // Create a new Apple and don't do any "polishing" here (will break reusability)
       return new Apple(dto) as TApple
    }

    protected override void Initialize(TFruitDto dto, TFruit objeto)
    {
       // Do the Apple "polishing" here
       // Call the Fruit "polish"
       base.Initialize(dto, objeto);
    }
}

如果需要创建另一个派生类(如BigApple和SmallApple),只需执行另一个工厂,不要在派生最多的CreateInstance中调用base.CreateInstance(dto),这样就只能执行“new”最衍生的类,抛光一直在层叠。

where子句有一些冗余,但它由DI封装,所以我认为它是好的。