我正在尝试编写工厂模式以在我的程序中创建MainMode或TestMode。我以前用来创建这些对象的代码是:
play = (isMode) ? new MainMode(numberRanges, numberOfGuesses) :
new TestMode(numberRanges, numberOfGuesses, randNo());
我的游戏(游戏)将根据布尔值(isMode)创建MainMode对象或TestMode对象。正如您所看到的,我在TestMode对象中添加了一个额外的值(randNo())。此值在TestMode中用于允许用户输入自己的“随机数”,而在MainMode构造函数中,这是随机生成的。在这个程序中,MainMode和TestMode都是抽象类Game的子类。
现在我想用Factory Pattern替换这一行,虽然我不确定我的TestMode构造函数需要一个额外的对象,我不确定我需要传递这个值的位置。如果我要创建一个工厂,它需要在一个新的类中,可能名为GameFactory或ModeFactory或类似的东西。
我该怎么做?
编辑:这里的问题是上面的代码在我的GUI中,其中numberRanges,numberOfGuesses和randNo()方法的值是。我想创建一个Factory类,但我无法传递这些值,因为randNo()会激活它自己。这是我的randNo()方法。
private int randNo() {
boolean isValidNumber = true;
int testRandomNum = 0;
while(isValidNumber) {
try {
testRandomNum = Integer.parseInt(JOptionPane.showInputDialog("Enter Random Number"));
isValidNumber = false;
} catch (NumberFormatException e) {
JOptionPane.showMessageDialog(null, "Sorry, but the number you entered was invalid");
}
}
return testRandomNum;
}
问题在于每当我传递randNo()时它都会显示JOptionPane。正如我已经说过的,GUI和Logic是分开的。 GUI位于GUI包中,而其余代码位于逻辑包中。
答案 0 :(得分:12)
请注意,其他一些答案可以说是工厂,但没有描述 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(); }
}
现在,如果您的整个应用程序只创建一个'模式,那么就不需要工厂了;当你需要反复创建相同的类类型时,你使用工厂;事实上,工厂只是一种创造正确类型(子)类的策略。
在生产代码中,我使用了工厂,我有一些创建东西的泛型类,我需要告诉如何创建正确的子类来创建;我通过工厂来做那件事。
现在我们为'模式创建一个工厂模式;这将与战略模式惊人相似:
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);
}
}
现在您了解工厂模式和策略模式,以及它们在“形状”中的相似之处,但它们的使用方式不同:工厂模式是Object Creational并返回要使用的对象;策略是对象行为,通常显式创建实例,并对实例进行引用,以封装算法。但就结构而言,它们非常相似。
编辑:OP在评论中询问“我如何将其集成到我的GUI中?”
嗯,这些都不属于你的程序的GUI,除了'模式。您将创建ConcreteStrategy并在某些安装例程中将其传递给首选Factory,可能根据命令行参数或配置文件确定要使用哪个。基本上,当您在原始帖子中选择正确的班级时,您会选择正确的工厂。 同样,如果你只创造某种东西,你就不需要工厂;工厂是大规模生产(或创建相关具体类型的家庭 - 虽然这超出了这个问题的范围)。
(假设我们有一个游戏,用户可以在命令行上选择是否与机器人或龙战斗;然后我们想要实例化一个产生Opponents(一个接口)的OpponentFactory,派生类RobotOpponent和DragonOpponent,以及将该工厂传递给spawnsNewOpponent()的游戏部分。同样,用户可能选择勇敢或懦弱的对手,我们将其设置为策略。我们不需要制作更多策略实例,因为策略是通常是幂等的(无国籍和单身)。)
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 );
}
答案 1 :(得分:1)
工厂的重点是它应该具备适当创建游戏所需的状态。
所以我会建造一个这样的工厂:
public class GameFactory {
private boolean testMode;
public GameFactory(boolean testMode) {
this.testMode = testMode;
}
public Game getGame(int numberRanges, int numberOfGuesses) {
return (testMode) ? new MainMode(numberRanges, numberOfGuesses) :
new TestMode(numberRanges, numberOfGuesses, getRandom());
}
private int getRandom() {
. . . // GUI code here
}
}
现在,您可以在应用程序中初始化此工厂somwhere,并将其传递给创建游戏所需的任何代码。这段代码现在不需要担心它是什么模式,并传递额外的随机参数 - 它使用一个众所周知的界面来创建游戏。所有需要的状态都由GameFactory对象内化。
答案 2 :(得分:0)
您的代码可能会更改为工厂模式。
类似的东西:
public static Mode createMode(boolean isMainMode)
{
if(isMainMode) return new MainMode(...);
return new TestMode(...);
}
将此方法放在合理的位置(这个很棘手,可能是静态ModeFactory)
这假设MainMode和TestMode是相同类型的子类型(子类或实现Mode接口)
现在所有玩法都要调用ModeFactory.createMode(...)并传递相应的布尔值。
编辑(响应OP更新):
在调用实际构造函数之前,会对rand()进行求值,并显示GUI。这就是激活自己的意思吗?
您必须在设计决策中决定模式。如果您有一个GUI并且您有一个模型,那么最好设计GUI以了解在调用工厂方法之前是否需要调用随机生成(和弹出),然后将随机数传递给工厂方法,让它只选择正确的构造函数。
反过来说(模型调用你的GUI)比较棘手,可能是个坏主意。
答案 3 :(得分:0)
尝试类似的事情,
abstract class ModeFactory {
public static Mode getMode(isMode, numberRanges, numberofGuesses) {
return isMode ? new MainMode(numberRanges, numberofGuesses) : new TestMode(numberRanges, numberOfGuesses, randNo());
}
public static Mode getMode(isMode, numberRanges, numberofGuesses, someNumber) {
return isMode ? new MainMode(numberRanges, numberofGuesses) : new TestMode(numberRanges, numberOfGuesses, someNumber);
}
}
该类是抽象的,只是为了停止初始化。您可以修改它以使用final,然后创建一个私有构造函数。
答案 4 :(得分:0)
interface ModeFactory {
Mode createMode(int numberRanges, int numberOfGuesses);
}
class MainModeFactory implements ModeFactory {
Mode createMode(int numberRanges, int numberOfGuesses) {
return new MainMode(numberRanges, numberOfGuesses);
}
}
class TestModeFactory implements ModeFactory {
Mode createMode(int numberRanges, int numberOfGuesses) {
return new TestMode(numberRanges, numberOfGuesses, randNo());
}
}
...
play = modeFactory.createMode(numberRanges, numberOfGuesses);
因此,在启动时,您可以创建适当的模式工厂,将其传递到需要创建游戏的任何位置。
答案 5 :(得分:0)
很简单,总是使用参数,如果没有使用参数,发送null
,如果你有其他“模式”的几个参数,将它们封装成一个参数。
答案 6 :(得分:0)
如果您只是在工厂方法之后,那将为您创建一个给定名称的类,请尝试:
public static MyInterface createClass(String name) throws IllegalAccessException,
InstantiationException, ClassNotFoundException {
try {
Class myClass = Class.forName(name);
MyInterface myObj = (MyInterface) myObj.newInstance();
return myObj;
} catch (ClassNotFoundException ex) {
logger.error("Could not find a class {}", name);
throw ex;
} catch (InstantiationException e) {
logger.error("Class must be concrete {}", name);
throw e;
} catch (IllegalAccessException e) {
logger.error("Class must have a no-arg constructor {}", name);
throw e;
}
}
答案 7 :(得分:0)
你真正想要做的是创建一个工厂,它返回一个抽象类或接口的对象(当然,它们是实现者)。然后在工厂方法中,您可以选择哪个实现者。如果您选择一个抽象类,您可以在其中实现一些通用逻辑,并让其他方法未实现(将它们声明为抽象)。您可以让混凝土下降器根据需要实施它们。这是工厂设计模式:
public class GridManagerFactory {
public static AbstractGridManager getGridManager(LifecicleAlgorithmIntrface lifecicleAlgorithm, String... args){
AbstractGridManager manager = null;
// input from the command line
if(args.length == 2){
CommandLineGridManager clManager = new CommandLineGridManager();
clManager.setWidth(Integer.parseInt(args[0]));
clManager.setHeight(Integer.parseInt(args[1]));
// possibly more configuration logic
...
manager = clManager;
}
// input from the file
else if(args.length == 1){
FileInputGridManager fiManager = new FileInputGridManager();
fiManager.setFilePath(args[0]);
// possibly more method calls from abstract class
...
manager = fiManager ;
}
//... more possible concrete implementors
else{
manager = new CommandLineGridManager();
}
manager.setLifecicleAlgorithm(lifecicleAlgorithm);
return manager;
}
}
抽象类中的commoun逻辑可用于其下行程序:
public abstract class AbstractGridManager {
private LifecicleAlgorithmIntrface lifecicleAlgorithm;
// ... more private fields
//Method implemented in concrete Manager implementors
abstract public Grid initGrid();
//Methods common to all implementors
public Grid calculateNextLifecicle(Grid grid){
return this.getLifecicleAlgorithm().calculateNextLifecicle(grid);
}
public LifecicleAlgorithmIntrface getLifecicleAlgorithm() {
return lifecicleAlgorithm;
}
public void setLifecicleAlgorithm(LifecicleAlgorithmIntrface lifecicleAlgorithm) {
this.lifecicleAlgorithm = lifecicleAlgorithm;
}
// ... more common logic and geter-seter pairs
}
具体实现者只需要实现声明为abstract的方法:
public class FileInputGridManager extends AbstractGridManager {
private String filePath;
@Override
public Grid initGrid() {
return this.initGrid(this.getFilePath());
}
public Grid initGrid(String filePath) {
List<Cell> cells = new ArrayList<>();
char[] chars;
File file = new File(filePath); // for ex foo.txt
// ... more logic
return grid;
}
}
AbstractGridManager的接收器将调用他的方法并获取逻辑,在具体的下行程序中实现(部分在抽象类方法中),而不知道他得到的具体实现是什么。这也像控制或依赖注入的反转