Factory Pattern可以构建许多派生类

时间:2015-04-27 23:05:02

标签: c# design-patterns factory-pattern

我有一个工厂对象ChallengeManager来为我正在构建的游戏生成Challenge对象的实例。有很多挑战。每个Challenge类派生的构造函数是不同的,但是它们之间有一个共同的接口,在基类中定义。

当我调用manager.CreateChallenge()时,它会返回Challenge的实例,这是派生类型之一。

理想情况下,我想在派生类本身内部保留对象构造的代码,因此与该对象相关的所有代码都是共存的。例如:

class Challenge {}

class ChallengeA : Challenge {
  public static Challenge MakeChallenge() {
    return new ChallengeA();
  }
}

class ChallengeB : Challenge {
  public static Challenge MakeChallenge() {
    return new ChallengeB();
  }
}

现在,我的ChallengeManager.CreateChallenge()来电只需要决定要拨打MakeChallenge()的班级。该结构的实施包含在类本身中。

使用此范例,每个派生类都必须定义静态MakeChallenge()方法。但是,由于该方法是静态的,我不能在这里使用接口,需要它。

这不是什么大问题,因为我可以很容易地记住为每个派生类添加正确的方法签名。但是,我想知道是否应该考虑更优雅的设计。

3 个答案:

答案 0 :(得分:21)

我非常喜欢你描述的模式并经常使用它。我喜欢这样做的方式是:

abstract class Challenge 
{
  private Challenge() {} 
  private class ChallengeA : Challenge 
  {
    public ChallengeA() { ... }
  }
  private class ChallengeB : Challenge 
  {
    public ChallengeB() { ... }
  }
  public static Challenge MakeA() 
  {
    return new ChallengeA();
  }
  public static Challenge MakeB() 
  {
    return new ChallengeB();
  }
}

这种模式有很多不错的属性。没有人可以制作新的Challenge,因为它是抽象的。没有人可以制作派生类,因为Challenge的默认ctor是私有的。没有人可以ChallengeAChallengeB获得,因为他们是私人的。您将接口定义为Challenge,这是客户端需要了解的唯一接口。

当客户想要A时,他们会问Challenge一个,然后他们就会得到它。他们不必担心幕后AChallengeA实施。他们只能获得他们可以使用的Challenge

答案 1 :(得分:2)

你"分散"工厂,每个子类负责创建自己。

更常见的是,您将拥有一个中心工厂,它可以了解可能的子类型以及如何构造它们(通常只需创建一个新实例并返回键入为公共接口或公共基类的实例)。这种方法可以避免您目前遇到的问题。我也认为你当前的方法没有任何好处。目前,您正在通过更典型的工厂实现获得封装或代码重用。

有关其他参考,请查看

http://www.oodesign.com/factory-pattern.html

答案 2 :(得分:1)

不一定是您要找的答案,但...... 如果你可以从每个类的静态方法中移开,你可以使用以下实现。

using System;

public class Test
{
    public static void Main()
    {
        var c1 = ChallengeManager.CreateChallenge();
        var c2 = ChallengeManager.CreateChallenge();
        //var c = ChallengeManager.CreateChallenge<Challenage>(); // This statement won't compile
    }
}

public class ChallengeManager
{
    public static Challenage CreateChallenge()
    {
        // identify which challenge to instantiate. e.g. Challenage1
        var c = CreateChallenge<Challenage1>();
        return c;
    }

    private static Challenage CreateChallenge<T>() where T: Challenage, new()
    {
        return new T();
    }
}

public abstract class Challenage{}
public class Challenage1: Challenage{}
public class Challenage2: Challenage{}