工厂模式构建很多派生类

Factory Pattern to build many derived classes

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

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

理想情况下,我想将对象构造代码保留在派生的 class 本身中,因此与该对象相关的所有代码都位于同一位置。示例:

class Challenge {}

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

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

现在,我的ChallengeManager.CreateChallenge()调用只需要决定class调用MakeChallenge()。构造的实现包含在 class 本身中。

使用此范例,每个派生 class 必须定义一个静态 MakeChallenge() 方法。但是,由于该方法是静态方法,因此我无法在此处使用需要它的接口。

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

你是"decentralizing"工厂,因此每个子class负责创建自己。

更常见的是,你会有一个中央工厂,它知道可能的子类型以及如何构造它们(通常情况下,只需创建一个新实例并将该实例类型化为公共接口或公共基class).这种方法避免了您当前遇到的问题。我也认为您当前的方法没有任何好处。您目前无法通过更典型的工厂实现获得任何封装或代码重用。

如需更多参考,请查看

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

我非常喜欢您描述的模式并且经常使用它。我喜欢的方式是:

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 因为它是抽象的。没有人可以派生 class 因为 Challenge 的默认构造函数是私有的。没有人可以到达 ChallengeAChallengeB,因为它们是私有的。您将接口定义为 Challenge,这是客户端需要理解的唯一接口。

当客户想要 A 时,他们会向 Challenge 索取,他们得到了。他们不需要担心 A 在幕后由 ChallengeA 实施的事实。他们只是得到一个可以使用的Challenge

不一定是您正在寻找的答案,但是... 如果您可以根据 class.

摆脱静态方法,则可以使用以下实现
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{}