Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/dart/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
用Java实现工厂模式的最佳方法_Java_Factory Pattern - Fatal编程技术网

用Java实现工厂模式的最佳方法

用Java实现工厂模式的最佳方法,java,factory-pattern,Java,Factory Pattern,我正在尝试编写一个工厂模式,以便在程序中创建MainMode或TestMode。我以前用来创建这些对象的代码是: play = (isMode) ? new MainMode(numberRanges, numberOfGuesses) : new TestMode(numberRanges, numberOfGuesses, randNo()); 我的游戏(play)将根据布尔值(isMode)创建MainMode对象或TestMode对象。如您所见,我

我正在尝试编写一个工厂模式,以便在程序中创建MainMode或TestMode。我以前用来创建这些对象的代码是:

play = (isMode) ? new MainMode(numberRanges, numberOfGuesses) : 
                  new TestMode(numberRanges, numberOfGuesses, randNo());
我的游戏(play)将根据布尔值(isMode)创建MainMode对象或TestMode对象。如您所见,我正在向TestMode对象(randNo())中添加一个额外的值。此值在TestMode中用于允许用户输入自己的“随机数”,而在MainMode构造函数中,此值是随机生成的。在这个程序中,MainMode和TestMode都是抽象类游戏的子类

现在我想用工厂模式替换这一行,尽管我不确定,因为我的TestMode构造函数需要一个额外的对象,我也不确定需要在哪里传递这个值。如果我要创建一个工厂,它需要在一个新的类中,可能命名为GameFactory或ModeFactory或类似的东西

我该怎么办

编辑:这里的问题是,上面的代码在我的GUI中,numberArranges、numberOfGuesses和randNo()方法的值都在这里。我想创建一个工厂类,但我无法传递这些值,因为randNo()会自动激活。这是我的randNo()方法


问题是,每当我传递randNo()时,它都会显示JOptionPane。正如我已经说过的,GUI和逻辑是分开的。GUI位于GUI包中,而其余代码位于逻辑包中。

您的代码可能会更改为出厂模式

比如:

public static Mode createMode(boolean isMainMode)
{
    if(isMainMode) return new MainMode(...);
    return new TestMode(...);
}
将此方法放置在合理的位置(此方法比较复杂,可能是静态模式工厂)

这假设MainMode和TestMode是相同类型的子类型(子类或实现模式接口)

现在需要做的就是调用ModeFactory.createMode(…)并传递相应的布尔值

编辑(响应OP更新):

在调用实际构造函数之前,会对rand()进行求值,并显示GUI。这就是你所说的自我激活吗

你必须在你想要决定模式的地方做出设计决定。如果您有一个GUI和一个模型,那么在调用factory方法之前,最好设计GUI以了解是否需要调用随机生成(和弹出),然后将随机数传递给factory方法,让它选择正确的构造函数

换一种方式(模型调用您的GUI)更复杂,而且可能是个坏主意

试试这样的事情

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,然后创建一个私有构造函数。

工厂的关键在于它应该具有适当创建游戏所需的状态

所以我会建一个这样的工厂:

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
   }
}

现在你可以在你的应用程序中初始化这个工厂,并将它传递给创建游戏所需的任何代码。这段代码现在不需要担心它是什么模式,也不需要传递额外的随机参数——它使用一个众所周知的界面来创建游戏。所有需要的状态都由GameFactory对象内部化。

注意,其他一些答案可能会描述工厂,但不会描述GOF工厂模式

现在我想用一个 工厂模式,尽管我不确定 因为我的TestMode构造函数需要 额外的物体,我不确定我在哪里 将需要传递此值

好吧,你可以这样想:MainMode,而不是TestMode,是一个做特殊事情的模式。它所做的特殊事情是忽略给定的数字,以确保它确实是随机的。从这个角度来看,MainMode做了一些额外的事情

或者,如果除了随机性之外,MainMode和TestMode没有什么不同,那么您可能会想,您可以将这种相似性划分为一个类,这是计算随机数的两种策略之一。一种策略实际上是随机的,另一种策略是反常的,随机范围只有1个值

但让我们假设MainMode和TestMode之间还有其他区别——可能TestMode会向System.out或其他东西输出额外的调试

我们仍然可以考虑“我们如何提供随机性”从我们是测试还是真正玩游戏。这些是正交的关注点

因此,现在我们知道,除了“模式”所做的其他事情外,它还应该接受随机性策略。然后我们可以,例如,当你被告知标准平台随机性实际上不够随机时,你可以用更好的随机性替换它

或者,您可以在随机范围仅限于两个选项的情况下进行测试,或者始终从一到零交替,或者在每次调用时返回某个向量器或迭代器中的下一个值

因此,我们使用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);
  }
}
现在你知道了工厂模式和战略模式,以及它们在“形状”上的相似性,但在使用方式上有所不同:Factory模式是对象创建模式,返回要使用的对象;策略是对象行为的,通常显式创建实例,并持有对实例的引用,以封装算法。但就结构而言,它们非常相似
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);
  }
}
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 ); 

}
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);
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;
    }
}
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;
    }
}
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
}
  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;
        }
    }