工厂模式构建很多派生类
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).这种方法避免了您当前遇到的问题。我也认为您当前的方法没有任何好处。您目前无法通过更典型的工厂实现获得任何封装或代码重用。
如需更多参考,请查看
我非常喜欢您描述的模式并且经常使用它。我喜欢的方式是:
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
的默认构造函数是私有的。没有人可以到达 ChallengeA
或 ChallengeB
,因为它们是私有的。您将接口定义为 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{}
我有一个工厂对象 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).这种方法避免了您当前遇到的问题。我也认为您当前的方法没有任何好处。您目前无法通过更典型的工厂实现获得任何封装或代码重用。
如需更多参考,请查看
我非常喜欢您描述的模式并且经常使用它。我喜欢的方式是:
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
的默认构造函数是私有的。没有人可以到达 ChallengeA
或 ChallengeB
,因为它们是私有的。您将接口定义为 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{}