请注意,其他一些答案可能可以说是描述工厂,但没有描述GOF 工厂模式。
现在我想用工厂模式替换这一行,尽管我不确定因为我的 TestMode 构造函数需要一个额外的对象,而且我不确定我需要在哪里传递这个值。
好吧,你可以这样想:MainMode,而不是 TestMode,是做一件特殊事情的那个。它所做的特殊事情是忽略给定的数字,以确保它真的是随机的。以这种方式思考,MainMode 做了一些额外的事情。
或者,如果除了随机性之外,MainMode 和 TestMode 没有什么不同,那么您可能会认为您可以将这种相似性分解为一个类,该类提供了用于计算随机数的两种策略之一。一种策略实际上是随机的,一种是反常的,随机范围只有 1 个值。
但是让我们假设 MainMode 和 TestMode 之间还有其他区别——大概是 TestMode 输出额外的调试到 System.out 或其他东西。
我们仍然可以将“我们如何提供随机性”从我们是在测试还是在玩真正的游戏中分解出来。这些是正交的问题。
所以现在我们知道,除了“模式”所做的任何其他事情外,它还应该接受随机策略。然后我们可以,例如,当你被告知标准平台随机数不够随机时,你可以用更好的随机数替换它。
或者您可以进行测试,其中随机数的范围仅限于两个选择,或者总是从一到零交替,或者在每次调用时返回某个 Vecrtor 或 Iterator 中的下一个值。
所以我们使用 GOF 策略模式来构建随机策略:
interface RandomStrategy {
public double random();
}
public class NotSoRandom implements RandomStrategy {
private double r;
public NotSoRandom( final double r ) { this.r = r; }
public double random() { return r; }
}
public class PlatformRandom implements RandomStrategy {
public double random() { return Math.random(); }
}
现在,如果您的整个应用程序只创建一个“模式”,则不需要工厂;当您需要一遍又一遍地创建相同的类类型时,您会使用工厂;工厂实际上只是一种创建正确类型(子)类的策略。
在生产代码中,我使用了工厂,其中我有一些创建东西的通用类,我需要告诉如何创建正确的子类来创建;我经过一家工厂来做那件事。
现在我们为 'Mode; 创建一个工厂模式;这将惊人地类似于策略模式:
abstract class Mode() {
private RandomStrategy r;
public Mode( final RandomStrategy r ) { this.r = r; }
// ... all the methods a Mode has
}
public class MainMode implements Mode {
public MainMode( final RandomStrategy r ) { super(r); }
}
public class TestMode implements Mode {
public TestMode( final RandomStrategy r ) { super(r); }
}
interface ModeFactory{
public Mode createMode( final RandomStrategy r );
}
public class MainFactory() {
public Mode createMode( final RandomStrategy r ) {
return new MainMode(r);
}
}
public class TestFactory() {
public Mode createMode( final RandomStrategy r ) {
return new TestMode(r);
}
}
所以现在您知道了工厂模式和策略模式,以及它们在“形状”上的相似之处,但在使用方式上却有所不同:工厂模式是创建对象并返回要使用的对象;策略是对象行为的,通常显式创建一个实例,并持有对该实例的引用,以封装算法。但就结构而言,它们非常相似。
编辑:OP 在评论中询问“我如何将它集成到我的 GUI 中?”
好吧,这些都不属于你的程序的 GUI,除了可能的“模式”。您将创建 ConcreteStrategy 并将其传递给某些设置例程中的首选工厂,可能会根据命令行参数或配置文件确定要使用的工厂。基本上,您会选择正确的工厂,就像您在原始帖子中选择正确的课程一样。再说一次,如果你只创建一个东西,你就不需要工厂。工厂用于大规模生产(或创建相关具体类型的系列——尽管这超出了这个问题的范围)。
(假设我们有一个游戏,用户可以在命令行上选择是打机器人还是打龙;那么我们想要实例化一个产生 Opponents(接口)的 OpponentFactory,具有派生类 RobotOpponent 和 DragonOpponent,并通过该工厂到生成NewOpponent()的游戏部分。类似地,用户可能会选择勇敢或懦弱的对手,我们将其设置为策略。我们不需要制作更多的策略实例,因为策略通常是幂等的(无状态和单身)。)
static int main( String[] args ) {
// setup game world
final RandomStrategy r = "random".equals(args[0])
? new PlatformRandom() : new NotSoRandom( Integer.intValue(args[0]) ) ;
// notice the simlarity to the code you originally posted;
// we factored out how to achieve "randomness" as a Strategy.
// now we will use our Strategy to setup our Factory;
final ModeFactory f = "test".equals(args[1])
? new TestFactory(r) : new MainFactory(r);
// also similar to your code
// we've just added an extra level of indirection:
// instead of creating a Mode, we've created an object that can create Modes
// of the right derived type, on demand.
// call something that uses our factory
functionThatRunsameAndNeedstoProduceModesWhenevertNeedsTo( f );
}