在Java中实现Factory Pattern的最佳方法 [英] Best way to implement the Factory Pattern in Java

查看:115
本文介绍了在Java中实现Factory Pattern的最佳方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

  play =(isMode)? new MainMode(numberRanges,numberOfGuesses):
new TestMode(numberRanges,numberOfGuesses,randNo());

My Game(play)会根据布尔值创建MainMode对象或TestMode对象( isMode)。正如您所看到的,我在TestMode对象中添加了一个额外的值(randNo())。此值在TestMode中使用,以允许用户输入自己的随机数,而在MainMode构造函数中,这是随机生成的。在这个程序中,MainMode和TestMode都是抽象类Game的子类。



现在我想用工厂模式替换这一行,虽然我不确定是我的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(输入随机数));
isValidNumber = false;
} catch(NumberFormatException e){
JOptionPane.showMessageDialog(null,抱歉,但您输入的数字无效);
}
}

返回testRandomNum;
}

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

解决方案

请注意其他一些答案可以说是工厂,但没有描述 GOF工厂模式


现在我想要更换这行带有
工厂模式,虽然我不确定
,因为我的TestMode构造函数需要一个
的额外对象,我不确定我
需要传递这个值。


嗯,你可以这样想:MainMode,而不是TestMode,是一个特殊的东西。它所做的特殊事情是忽略给定的数字,以确保它真的是随机的。以这种方式思考它,它的MainMode做了额外的事情。



或者,如果除了随机性,MainMode和TestMode没有区别,那么你就是想也许你可以将这种相似性分解为一个类,这是计算随机数的两种策略之一。一个策略实际上是随机的,一个是有悖常理的,随机范围只有1个值。



但我们假设MainMode和TestMode之间存在其他差异 - - 大概是TestMode向System.out或其他东西输出额外的调试。



我们仍然可以分析我们如何提供随机性来自我们测试或玩真实的游戏。这些是正交问题。



所以现在我们知道除了'模式所做的其他事情之外,它应该接受随机性策略那么我们可以,例如,当你被告知标准平台随机不够随机时,你可以用更好的随机替换它。



或者您可以测试范围的范围仅限于两个选项,或者总是从一个替换为零,或者在每次调用时返回一些Vecrtor或Iterator中的下一个值。



因此我们使用GOF策略模式来构建随机数ss策略:

  interface RandomStrategy {
public double random();
}

公共类NotSoRandom实现RandomStrategy {
private double r;
public NotSoRandom(final double r){this.r = r; }
public double random(){return r; }
}

公共类PlatformRandom实现RandomStrategy {
public double random(){return Math.random(); }
}

现在,如果您的整个应用只创建一个'模式,那就没有了需要工厂;当你需要反复创建相同的类类型时,你使用工厂;工厂实际上只是一个创建正确类型(子)类的策略。



在生产代码中,我使用的工厂里面有一些通用类,创建东西,我需要告诉如何创建正确的子类来创建;我通过工厂来做到这一点。



现在我们为'模式创建一个工厂模式;这将与策略模式惊人相似:

 抽象类Mode(){
private RandomStrategy r;
公共模式(最终的RandomStrategy r){this.r = r; }
// ...模式有
的所有方法}

公共类MainMode实现Mode {
public MainMode(final RandomStrategy r){super(r ); }
}

公共类TestMode实现Mode {
public TestMode(final RandomStrategy r){super(r); }
}

接口ModeFactory {
public Mode createMode(final RandomStrategy r);
}

公共类MainFactory(){
public Mode createMode(final RandomStrategy r){
return new MainMode(r);
}
}

公共类TestFactory(){
public Mode createMode(final RandomStrategy r){
return new TestMode(r);
}
}

现在你知道了工厂模式和战略模式,以及它们在形状上的相似之处,但它们的使用方式不同:工厂模式是Object Creational并返回一个要使用的对象;策略是对象行为,通常显式创建实例,并对实例进行引用,以封装算法。但就结构而言,它们非常相似。



编辑:OP在评论中询问我如何将其集成到我的GUI中? / p>

嗯,这些都不属于你的程序的GUI,除了可能是'模式。您将创建ConcreteStrategy并在某些安装例程中将其传递给首选Factory,可能根据命令行参数或配置文件确定要使用哪个。基本上,当您在原始帖子中选择正确的课程时,您会选择正确的工厂。 同样,如果你只创造某种东西,你就不需要工厂;工厂是大规模生产(或创建相关具体类型的家庭 - 虽然这超出了这个问题的范围)。



(假设我们有一个游戏用户可以在命令行上选择是否与机器人或龙对战;然后我们想要实例化一个OpponentFactory,它产生Opponents(一个接口),派生类RobotOpponent和DragonOpponent,并将该工厂传递给游戏的一部分同样,用户可能选择勇敢或懦弱的对手,我们将其设置为策略。我们不需要制作更多策略实例,因为策略通常是幂等的(无状态和单身)。)

  static int main(String [] args){
//设置游戏世界

final RandomStrategy r =random.equals(args [0])
? new PlatformRandom():new NotSoRandom(Integer.intValue(args [0]));
//注意你最初发布的代码的相似性;
//我们考虑了如何将随机性作为一种策略。

//现在我们将使用我们的策略来设置我们的工厂;

final ModeFactory f =test.equals(args [1])$ ​​b $ b?新的TestFactory(r):新的MainFactory(r);
//也类似于你的代码
//我们刚刚添加了一个额外的间接级别:
//而不是创建一个Mode,我们创建了一个可以创建Modes的对象根据需要,
//右派生类型。

//调用使用我们工厂的东西
functionThatRunsameAndNeedstoProduceModesWhenevertNeedsTo(f);

}


I am trying to write a Factory Pattern to create either a MainMode or a TestMode in my program. The code I was previously using to create these objects was:

play = (isMode) ? new MainMode(numberRanges, numberOfGuesses) : 
                  new TestMode(numberRanges, numberOfGuesses, randNo());

My Game (play) would either create a MainMode object or a TestMode object depending on a boolean value (isMode). As you can see I am adding an extra value into my TestMode object (randNo()). This value is used within TestMode to allow the user to input their own "Random Number", whereas within the MainMode constructor this was randomly generated. In this program both MainMode and TestMode are sub-classes of the abstract class Game.

Now I want to replace this line with a Factory Pattern, although I am unsure as my TestMode constructor requires an extra object and I am unsure where I would need to pass this value. If I were going to create a Factory it'd need to be in a new class, probably named GameFactory or ModeFactory or something along those lines.

How would I go about this?

EDIT: The problem here is that the code above is in my GUI, where the values for numberRanges, numberOfGuesses and the randNo() method are. I want to create a Factory class but I am unable to pass these values through because randNo() activates itself. Here is my randNo() method.

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

The problem is that whenever I pass randNo() it displays the JOptionPane. As I've said already the GUI and Logic is separate. The GUI is in a GUI package whilst the rest of the code is in the logic package.

解决方案

Note that some of the other answers may arguably describe factories, but don't describe the GOF Factory Pattern.

Now I want to replace this line with a Factory Pattern, although I am unsure as my TestMode constructor requires an extra object and I am unsure where I would need to pass this value.

Well, you could think of it this way: MainMode, not TestMode, is the one that does a special thing. The special thing it does, is to ignore the given number, in order to ensure it's really random. In this way of thinking about it, it's MainMode that does something extra.

Or, if other than the randomness, MainMode and TestMode are not different, then you'd be thinking perhaps that you can factor out that similarity into one class, which is provided one of two Strategies for calculating random numbers. One Strategy would actually be random, and one would be perverse, with a random range of only 1 value.

But let's assume that there are other differences between MainMode and TestMode -- presumably TestMode outputs extra debugging to System.out or something.

We can still factor out "how do we supply randomness" from are we testing or playing the game for real". These are orthogonal concerns.

So now we know that in addition to whatever else a 'Mode does, it should accept a Randomness Strategy. Then we could, for example, when you're told that the standard platform random isn't really random enough, you can replace it with a better random.

Or you can do testing where the range of randoms is constrained to only two choices, or always alternates from one to zero, or returns on each call the next value in some Vecrtor or Iterator.

So we use the GOF Strategy Pattern to build the randomness strategies:

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

Now, if your whole app only ever creates one 'Mode, there's no need for a factory; you use a factory when you need to create the same class type over and over; the Factory is in fact just a Strategy for creating the right kind of (sub) class.

In production code, I've used factories where I have some generic class that creates stuff, and I need to tell how to create the right subclass to create; I pass in a factory to do that.

Now we create a Factory pattern for the 'Mode; this will be surprisingly similar to the Strategy pattern:

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

So now you know about the Factory Pattern and Strategy Pattern, and how they're similar in "shape", but different in how they're used: Factory Pattern is Object Creational and returns an object to be used; Strategy is Object Behavioral, and an instance is usually created explicitly and a reference is held to the instance, to encapsulate an algorithm. But in terms of the structure, they're quite similar.

Edit: the OP asks, in a comment, "How would I integrate this into my GUI?"

Well, none of this belongs in the GUI of your program, except possibly the 'Mode. You'd create the ConcreteStrategy and pass it to the preferred Factory in some setup routine, possibly determining which to use based on command line arguments or config files. basically, you'd select the correct factory very much as you selecting the correct class in your original post. Again, if you're only ever creating one of something, you don't need a Factory; factories are for mass production (or creating families of related concrete types -- though that's beyond the scope of this question).

(Assume we have a game where the user can select on the command line whether to fight robots or dragons; then we'd want to instantiate an OpponentFactory that produce Opponents (an interface), with derived classes RobotOpponent and DragonOpponent, and pass that factory to the part of the game that spawnsNewOpponent(). Similarly, a user might select brave or cowardly opponents, which we'd set up as a Strategy. We don't need to make more Strategy instances, as a Strategy is usually idempotent (stateless and singleton).)

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

}

这篇关于在Java中实现Factory Pattern的最佳方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆