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()方法。 但是,由于该方法是静态的,我不能在这里使用接口,需要它。

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

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

 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询问一个,然后他们就会得到它。 他们不需要担心幕后的事实, A是由ChallengeA实施的。 他们只是得到了他们可以使用的Challenge

你正在“分散”工厂,这样每个子类都负责创建自己。

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

有关其他参考,请查看

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

不一定是您正在寻找的答案,但是……如果您可以远离每个类的静态方法,您可以使用以下实现。

 using System; public class Test { public static void Main() { var c1 = ChallengeManager.CreateChallenge(); var c2 = ChallengeManager.CreateChallenge(); //var c = ChallengeManager.CreateChallenge(); // This statement won't compile } } public class ChallengeManager { public static Challenage CreateChallenge() { // identify which challenge to instantiate. eg Challenage1 var c = CreateChallenge(); return c; } private static Challenage CreateChallenge() where T: Challenage, new() { return new T(); } } public abstract class Challenage{} public class Challenage1: Challenage{} public class Challenage2: Challenage{}