Newbie: Factory Template in Java

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

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

My Game (play) will either create a MainMode object or a TestMode object depending on the boolean value (isMode). As you can see, I am adding extra value to my TestMode object (randNo ()). This value is used in TestMode to allow the user to enter their own "Random Number", while in the MainMode constructor this was randomly generated. In this program, MainMode and TestMode are subclasses of the abstract class game.

Now I want to replace this line with the Factory pattern, although I'm not sure, since my TestMode constructor requires an additional object, and I'm not sure where I will need to pass this value. If I was going to create a Factory, it would have to be in a new class, probably called GameFactory or ModeFactory or something like that.

How can i do this?

EDIT: The problem is that the above code is in my GUI, where the values ​​are for numberRanges, numberOfGuesses and the randNo () method. I want to create a Factory class, but I cannot pass these values ​​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 JOptionPane. As I said, GUI and logic are separate. The GUI is in the GUI package, while the rest of the code is in the logical package.

+5
java factory-pattern
source share
8 answers

Please note that some other answers may possibly describe factories, but do not describe the GOF Factory pattern.

Now I want to replace this line with a Factory Sample, although I'm not sure because my TestMode constructor requires an additional object, and I'm not sure where I will need to pass this value.

Well, you could think of it this way: MainMode, not TestMode, is the one that does the special thing. Particularly what he does is to ignore the given number to ensure it is truly random. In this way of thinking about it, MainMode does something extra.

Or, if this is different from randomness, MainMode and TestMode are not different from each other, then you might think that you can take this similarity into account in one class, which is provided with 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 suppose there are other differences between MainMode and TestMode - presumably TestMode outputs additional debugging to System.out or something like that.

We can still rule out “how can we put an accident” because we are testing or playing a game for real. ”These are orthogonal problems.

So now we know that in addition to what the “Mode” is still doing, it must adopt the Strategy of chance. Then we could, for example, when you were told that the standard random platform is not random enough, you can replace it with a better random one.

Or you can conduct a test where the range of randomness is limited to only two options or always alternates from one to zero or returns the next value on each call in some Vecrtor or Iterator.

Thus, we use the GOF strategy template to build random 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 application only ever creates one “mode”, there is no need for a factory; you use Factory when you need to create the same class type again; Factory is actually just a strategy for creating an appropriate type of (sub) class.

In production code, I used factories where I have some kind of general class that creates material, and I need to say how to create the right subclass to create; For this, I pass Factory.

Now we create a Factory template for the mode; it will be surprisingly similar to the Strategy template:

 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 template and strategy template and how they are similar in “form”, but differ in how they are used: Factory Template - Object Creational and returns the object that should be used; The strategy is Object Behavioral, and the instance is usually created explicitly, and the link is placed in the instance to encapsulate the algorithm. But in terms of structure, they are very similar.

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

Well, none of this belongs to the graphical interface of your program, except, possibly, “Mode”. You will create a ConcreteStrategy and transfer it to your preferred Factory in some installation procedure, possibly determining which one to use based on command line arguments or configuration files. basically, you would choose the right Factory very much by choosing the right class in your original post. Again, if you only ever create something, you don't need a factory; factories for mass production (or the creation of families of related specific types, although this is beyond the scope of this issue).

(Suppose we have a game in which the user can choose on the command line whether to fight robots or dragons, then we want to create an instance of OpponentFactory that creates opponents (interface), with derived classes RobotOpponent and DragonOpponent and pass that Factory to the part of the game that spawns NewOpponent (). Likewise, the user can select brave or cowardly opponents that we would install as Strategy. We do not need to create more copies of Strategy, as Strategy is usually idempotent (stateless and single ).)

 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 ); } 
+12
source share

The whole point of the Factory is that it must have the necessary state to properly create the game.

So, I would build Factory as follows:

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

Now you can initialize this Factory somwhere in your application and pass it to any code needed to create the game. This code now does not need to worry about what mode it is in, and pass additional random parameters - it uses a well-known interface for creating games. All necessary state is internalized by the GameFactory object.

+1
source share

Perhaps your code has been changed to a factory pattern.

Something like:

 public static Mode createMode(boolean isMainMode) { if(isMainMode) return new MainMode(...); return new TestMode(...); } 

Put this method somewhere reasonable (this complicated, maybe static ModeFactory)

This assumes that MainMode and TestMode are subtypes of the same type (subclasses or implementation mode interface)

Now all games should consist in a call to ModeFactory.createMode (...) and pass the corresponding logical value.

Edit (in response to an OP update):

Your rand () gets evaluated before calling the actual constructor and presents a graphical interface. Is that what you mean by activating yourself?

You must make a design decision in which you want to make a decision about the regime. If you have a graphical interface and you have a model, it might be preferable to design a graphical interface to find out if you need to call random generation (and a popup) before calling the factory method, and then pass the random number to the factory method and let it just selects the correct constructor.

On the other hand (the model calls your GUI) is more complicated and probably a bad idea.

0
source share

Try something like

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

The class is abstract to stop the initialization. You can change it to use final, and then create a private constructor.

0
source share
 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); 

So, at startup, you create the appropriate factory mode, passing it to where you want to create the game.

0
source share

Very simple, ALWAYS USE THE PARAMETER, if the parameter is not used, send null , if you have several parameters for other "Modes", encapsulate them in one parameter.

0
source share

If you are only after the factory method, which will create a class for this name for you, try this:

 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; } } 
0
source share

What you really want to do is make a factory that returns an object of an abstract class or interface (of course, their executors). In the factory method, you choose which option to choose. If you choose an abstract class, you can implement some general logic in it and let other methods not implement it (declaring them abstract). You would allow concrete slopes to realize them depending on their needs. This is the factory design template:

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

Local logic in an abstract class is available for its descenders:

 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 } 

A specific developer only needs a method declared 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; } } 

The receiver of the AbstractGridManager will call the methods on it and get the logic implemented in concrete descenders (and partially in the abstract methods of the class), not knowing what specific implementation it received. This is also known as inversion of control or dependency injection.

0
source share

All Articles