【问题标题】:Implement Factory pattern using Generics once and for all一劳永逸地使用泛型实现工厂模式
【发布时间】:2014-04-01 23:07:05
【问题描述】:

考虑一下。我想创建一个创造动物的工厂(模式,而不是计划新的起源)。我以为我会很聪明,并创建一个包含我需要的 3 件东西的类,

  • 返回抽象动物的委托
  • 为每个动物返回特定动物的创建方法
  • 使用委托的每个创建方法的实例

厌倦了再次这样做并获得每次我需要使用工厂模式时,我想我会更加聪明并一劳永逸地解决它。所以,我创建了这个漂亮的类

class Factorable<T> where T: class, new() 
{
    delegate T CreateDelegate();
    static CreateDelegate DoCreate = new CreateDelegate (CreateSelf);
    static T CreateSelf()
    {
        return new T();
    }
}

class Factory<T> where T : Factorable<T>
{
    public Factorable<T>.CreateDelegate CreationMethod ;
} 

我想,很酷,我可以让顶级类(Animal)继承这个类,这样我就不必为所有动物编写和实例化所有具体的创建方法。多亏了泛型,这一切都将完成。几乎……看到这个:

class Animal:Factorable<Animal> {...}
class Bird:Animal {...}

Factory genesis = new Factory<Animal>();
genesis.CreationMethod = Animal.DoCreate;
Animal instance = genesis.CreateAnimal();  //instance is a brand new abstract Animal

genesis.CreationMethod = Bird.DoCreate;  //lets make it create birds!
instance = genesis.CreateAnimal();  // wrong, instance is still an abstract Animal

有没有办法解决这个问题?我想要 Bird 继承的 CreateSelf 方法来创建 Birds,而不是抽象 Animals(无需为 Bird 编写新方法)。有没有办法指定 Animal 继承自 Factorable 但让其后代用自己的类型覆盖泛型 T?

像这样的东西(这是愚蠢的代码,不起作用)

class Animal:Factorable<Animal... or better the actual type of the class that has inherited>

【问题讨论】:

  • 也许我遗漏了一些东西,但是Animal 如何从自身的泛型Factorable&lt;Animal&gt; 继承?
  • @MikeC 这在 C# 中是可能的。

标签: c# oop generics inheritance


【解决方案1】:

你是不是有点过于复杂了?假设 Animal 是您的基类:

public class Factory
{
    public static T Create<T>() where T : Animal, new()
    {
        return new T();
    }
}

用法:

var a = Factory.Create<Animal>();
var b = Factory.Create<Bird>();

更新

阅读您的评论后,我是这样理解的:调用工厂的对象不知道创建实例的确切类型。它只知道它是动物或动物派生类。那么,这个怎么样:

public class Factory
{
    private Type _outputType = typeof(Animal);

    public void Produces<T>() where T : Animal, new()
    {
        _outputType = typeof(T);
    }

    public Animal CreateAnimal()
    {
        return (Animal)Activator.CreateInstance(_outputType);
    }
}

注意:将输出类型设为私有并使用Produces&lt;T&gt; 设置它提供了一种简单的方法来确保输出类型是动物或派生。

用法:

var f = new Factory();  // factory produces animals
var a = f.CreateAnimal();
f.Produces<Bird>();     // from now on factory produces birds
var b = f.CreateAnimal();

【讨论】:

  • 工厂创建高级对象,允许其他需要它的类创建抽象类型。但是,它应该允许您将后代类类型注入到已经完成的层次结构中。这就是我的代表的原因。假设我有一个库来处理带有 Cage 类的动物园。笼子使用工厂来创造动物。 AnimalHandler 类也是。整个库完成并密封在一个 DLL 中。现在我想创建一个 Aviary 应用程序。理想情况下,有一种方法可以告诉工厂:好的,不要创建动物,请只创建鸟类(我的代表)。
  • 更新了我的答案。请注意,变量b 仍然是Animal 类型,但拥有Bird 类的实例。这是你想要的吗?
  • 酷!这正是我一直在寻找的。给你的绿色复选标记。
【解决方案2】:

你不能用静态方法做到这一点。试试这个:

class Factorable<T> where T: class, new() 
{
    delegate T CreateDelegate();
    CreateDelegate DoCreate = new CreateDelegate (CreateSelf);
    T CreateSelf()
    {
        return new T();
    }
}
class Animal : Factorable<Animal>...
...
Factory genesis = new Factory();
genesis.CreateAnimal = (new Animal()).DoCreate;
Animal instance = genesis.CreateAnimal(); 

genesis.CreateAnimal = (new Bird()).DoCreate;
instance = genesis.CreateAnimal();

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-09-16
    • 2015-09-25
    • 2016-07-20
    • 2017-06-16
    • 1970-01-01
    • 2016-09-13
    • 1970-01-01
    相关资源
    最近更新 更多