我有一个工厂对象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()
方法。但是,由于该方法是静态的,我不能在这里使用接口,需要它。
这不是什么大问题,因为我可以很容易地记住为每个派生类添加正确的方法签名。但是,我想知道是否应该考虑更优雅的设计。
答案 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是私有的。没有人可以ChallengeA
或ChallengeB
获得,因为他们是私人的。您将接口定义为Challenge
,这是客户端需要了解的唯一接口。
当客户想要A
时,他们会问Challenge
一个,然后他们就会得到它。他们不必担心幕后A
由ChallengeA
实施。他们只能获得他们可以使用的Challenge
。
答案 1 :(得分:2)
你"分散"工厂,每个子类负责创建自己。
更常见的是,您将拥有一个中心工厂,它可以了解可能的子类型以及如何构造它们(通常只需创建一个新实例并返回键入为公共接口或公共基类的实例)。这种方法可以避免您目前遇到的问题。我也认为你当前的方法没有任何好处。目前,您正在通过更典型的工厂实现获得封装或代码重用。
有关其他参考,请查看
答案 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{}