• No results found

Replacing a constructor with the Factory pattern

In document NetBeans IDE 8 Cookbook (Page 102-106)

How it works…

The NetBeans Encapsulate Fields refactoring allows the developer to add getters and setters to any or all of the properties within a class. As has been seen in this recipe, encapsulating a field allows developers to write more robust code; however, care must be taken. Encapsulating arrays or objects within a class must be considered carefully before being implemented.

Remember to ensure that the array or object itself can't be modified, but what it represents can be.

There's more...

When creating accessors, the Insert Point dropdown specifies where in the code the accessors are added. This can be as First Method or Last Method or after/before any other accessors. Accessors can be sorted in pairs, in alphabetic order, or with getters before setters.

Check out the Sort By field to perform this.

The visibility of fields can be changed by setting the Fields' Visibility dropdown to private, protected, or public. Similarly, the accessors' visibility can be set by modifying the Accessors' Visibility dropdown.

The field encapsulation refactoring can also generate Javadoc for the accessors. Default comments can be generated or the Javadoc from the fields themselves can be copied over into the accessors.

Replacing a constructor with the Factory pattern

A good development practice can be to use factory methods instead of class constructors.

Factory methods can be more descriptive than constructors and can perform additional

Getting ready

First we will need a Java project so that we can replace a class constructor with a factory method. We will use the same project from the earlier recipe, Rename refactoring, and so ensure that you have the project open from the end of that recipe. If you have not followed that recipe, the project is available from the code download bundle under the MoveRefactor folder in Chapter 3. When the Projects explorer shows the Refactoring project, expand the Refactoring node if not yet expanded.

How to do it…

Suppose we are writing a game and want to implement different levels. Increasing levels of the game could be more complex than the previous levels but each level offers a constant set of challenges and objectives. We could easily represent this with a basic model of a GameLevel class, which takes an integer difficulty as a constructor parameter. We could then refactor to replace the constructor with a factory to make the code more robust. In fact, let's do just that!

1. Right-click on the com.davidsalter.cookbook.refactor package and select New and then Java Class….

2. Enter GameLevel in the Class Name field.

3. In the Package selection, enter com.davidsalter.cookbook.

refactor.factory. 4. Click on Finish.

5. The GameLevel class will now be created and opened for editing. Change the contents of the class to be as follows:

public class GameLevel { private int difficulty;

public GameLevel(int difficulty) { this.difficulty = difficulty;

} }

This simple class now represents a game level that has differing degrees of difficulty.

Let's now change the constructor to use the Factory pattern with the following steps:

1. Right-click on the body of the constructor in the GameLevel.java class and select Refactor and then Replace Constructor with Factory….

2. The Replace Constructor With Factory dialog will now be displayed:

3. Enter levelWithDifficulty in the Factory Method Name field.

4. Click on Refactor.

5. The Replace Constructor With Factory dialog will now close and the refactoring will be applied to the GameLevel.java class.

How it works…

Upon refactoring a constructor into a factory, the new factory method is created that instantiates the GameLevel class and returns it to the caller. The original constructor for the class is marked as private to stop callers directly instantiating the GameLevel class.

The updated code of the GameLevel class is:

public class GameLevel {

public static GameLevel levelWithDifficulty(int difficulty) { return new GameLevel(difficulty);

}

private int difficulty;

private GameLevel(int difficulty) { this.difficulty = difficulty;

} }

Looking at this code, we can immediately see that the name of the factory method is a lot more meaningful than the name of the constructor with its single parameter.

You can also imagine how it would be easy to create a cached lookup of all the levels available within the game and return a level from cache within the factory method rather than instantiating a new GameLevel each time the factory method is called. In a real game, it would be easy to believe that constructing GameLevel could be an expensive task in terms of CPU performance and time. Since GameLevel is essentially immutable, there's no need to instantiate a new one each time it is requested. Returning GameLevel from cache would be a

There's more...

Sometimes the Factory pattern is not the best way to instantiate an object—we may wish to user the Builder pattern instead.

Replacing constructors with the Builder pattern

If a constructor becomes more complex than a few parameters, or multiple operations are required to create an object, then the Builder pattern can be used to create objects instead of the Factory pattern.

NetBeans can apply the Builder pattern to classes enabling constructors to be replaced with a Builder pattern implementation. To replace a constructor with a Builder pattern, right-click on the body of a constructor and select Refactor and then Replace Constructor with Builder….

The Replace Constructor With Builder dialog will be displayed:

In document NetBeans IDE 8 Cookbook (Page 102-106)