java static factory methods

32
JAVA CONSIDER STATIC FACTORY METHODS INSTEAD OF CONSTRUCTORS Ye Win 11/21/2015

Upload: ye-win

Post on 13-Apr-2017

629 views

Category:

Technology


1 download

TRANSCRIPT

Page 1: Java Static Factory Methods

JAVACONSIDER STATIC FACTORY METHODS INSTEAD OF CONSTRUCTORS

Ye Win11/21/2015

Page 2: Java Static Factory Methods

Contents• Preface (Summary)

• Static Factory Methods

• Advantages

• Disadvantages

• Summary (Preface)

Page 3: Java Static Factory Methods

Preface (Summary)In preface, static factory methods and public constructors both have their uses, and it pays to understand their relative merits. Often static factories are preferable, so avoid the reflex to provide public constructors without first considering static factories.

Page 4: Java Static Factory Methods

Static Factory Methods• The normal way for a class to allow a client to obtain an instance of

itself is to provide a public constructor. There is another technique that should be a part of every programmer’s toolkit.

• A class can provide a public static factory method, which is simply a static method that returns an instance of the class.

Page 5: Java Static Factory Methods

Static Factory MethodsHere’s a simple example from Boolean (the boxed primitive class for the primitive type boolean). This method translates a boolean primitive value into a Boolean object reference:

public static Boolean valueOf(boolean b) {return b ? Boolean.TRUE : Boolean.FALSE;

}

A class can provide its clients with static factory methods instead of, or in addition to, constructors. Providing a static factory method instead of a public constructor has both advantages and disadvantages.

Page 6: Java Static Factory Methods

AdvantagesFirst advantage of static factory methods is that, unlike constructors, they have names.

• If the parameters to a constructor do not, in and of themselves, describe the object being returned, a static factory with a well-chosen name is easier to use and the resulting client code easier to read.

• Now let’s seen by an example.

Page 7: Java Static Factory Methods

Advantages• Look at the following example.

• We have a RandomIntGenerator class that, as the name suggests, generates random int numbers. Something like:

public class RandomIntGenerator { private final int min; private final int max;

public int next() {...} }

Page 8: Java Static Factory Methods

Advantages• Our generator takes a minimum and maximum and then generates

random numbers between those 2 values. Notice that the two attributes are declared final so we have to initialize them either on their declaration or in the class constructor. Let’s go with the constructor:

public RandomIntGenerator(int min, int max) { this.min = min; this.max = max;

}

Page 9: Java Static Factory Methods

Advantages• Now, we also want to give our clients the possibility to specify just a

minimum value and then generate random values between that minimum and the max possible value for ints. So we add a second constructor:

public RandomIntGenerator(int min) { this.min = min; this.max = Integer.MAX_VALUE;

}

Page 10: Java Static Factory Methods

Advantages• So far so good, right? But in the same way that we provided a

constructor to just specify the minimum value, we want to do the same for just the maximum. We’ll just add a third constructor like:

public RandomIntGenerator(int max) { this.min = Integer.MIN_VALUE; this.max = max;

}

• If you try that, you’ll get a compilation error that goes: Duplicate method RandomIntGenerator(int) in type RandomIntGenerator. What’s wrong?

Page 11: Java Static Factory Methods

Advantages• Full script:public class RandomIntGenerator {

private final int min; private final int max;

public int next() {...}

public RandomIntGenerator(int min, int max) { this.min = min; this.max = max; }

public RandomIntGenerator(int min) { this.min = min; this.max = Integer.MAX_VALUE; }

/* Compilation error will be occurred. */public RandomIntGenerator(int max) { this.min = Integer.MIN_VALUE; this.max = max; }

}

Page 12: Java Static Factory Methods

Advantages• The problem is that constructors, by definition, have no names. As

such, a class can only have one constructor with a given signature in the same way that you can’t have two methods with the same signature (same return type, name and parameters type). 

• That is why when we tried to add the RandomIntGenerator(int max) constructor we got that compilation error, because we already had the RandomIntGenerator(int min) one.

Page 13: Java Static Factory Methods

Advantages• Now let’s apply static factories to our RandomIntGenerator example, we could get:

public class RandomIntGenerator { private final int min; private final int max; // private constructor to non-institate class private RandomIntGenerator(int min, int max) { this.min = min; this.max = max; } public static RandomIntGenerator between(int max, int min) { return new RandomIntGenerator(min, max); } public static RandomIntGenerator biggerThan(int min) { return new RandomIntGenerator(min, Integer.MAX_VALUE); }

public static RandomIntGenerator smallerThan(int max) { return new RandomIntGenerator(Integer.MIN_VALUE, max); }

public int next() {...}}

Page 14: Java Static Factory Methods

Advantages• Note : How the constructor was made private to ensure that the

class is only instantiated through its public static factory methods.

• Also note how your intent is clearly expressed when you have a client with RandomIntGenerator.between(10,20) instead of

new RandomIntGenerator(10,20)

• Point is clear, we replace the constructors with static factory methods and carefully chosen names to highlight their differences.

Page 15: Java Static Factory Methods

AdvantagesA second advantage of static factory methods is that, unlike constructors, they are not required to create a new object each time they’re invoked.

This is extremely useful when working with immutable classes to provide constant objects for common used values and avoid creating unnecessary duplicate objects. (You can refer avoid creating uncessary objects in this link

http://www.slideshare.net/mysky14/avoid-creating-unncessary-objects)

Page 16: Java Static Factory Methods

Advantagespublic static Boolean valueOf(boolean b) {

return b ? Boolean.TRUE : Boolean.FALSE;}

• The Boolean.valueOf code that I showed previously illustrates this point perfectly. Notice that this static method returns either TRUE or FALSE, both immutable Boolean objects.

• This technique is similar to the Flyweight pattern (I am promise I will post about this

pattern in near future, please don’t forget to following me at slideshare.). It can greatly improve performance if equivalent objects are requested often, especially if they are expensive to create.

Page 17: Java Static Factory Methods

AdvantagesA third advantage of static factory methods is that, unlike constructors, they can return an object of any subtype of their return type.

• This gives you great flexibility in choosing the class of the returned object.

• Moreover, you can hide implementation classes and have an interface-based API (I am promise I will post about this interface-based framework in near future, please don’t forget to following

me at slideshare.), which is usually a really good idea.

• But I think this can be better seen by an example.

Page 18: Java Static Factory Methods

Advantages• Look at the following example.

• Imagine that we now want to provide random generators not just for integers but for other data-types like String, Double or Long. They are all going to have a next() method that returns a random object of a particular type, so we could start with an interface like:

public interface RandomGenerator<T> { T next();}

Page 19: Java Static Factory Methods

Advantages• Our first implementation of the RandomIntGenerator now becomes:

class RandomIntGenerator implements RandomGenerator<Integer> { private final int min; private final int max;

RandomIntGenerator(int min, int max) { this.min = min; this.max = max; }

public Integer next() {...}}

Page 20: Java Static Factory Methods

Advantages• We could also have a String generator:

class RandomStringGenerator implements RandomGenerator<String> { private final String prefix;

RandomStringGenerator(String prefix) { this.prefix = prefix; }

public String next() {...}}

Page 21: Java Static Factory Methods

Advantages• Notice how all the classes are declared package-private (default scope) and so are

their constructors. This means that no client outside of their package can create instances of these generators. So what do we do? Tip: It starts with “static” and ends with “methods”. Consider the following class:

public final class RandomGenerators { // Suppresses default constructor, ensuring non-instantiability. private RandomGenerators() {}

public static final RandomGenerator<Integer> getIntGenerator() { return new RandomIntGenerator(Integer.MIN_VALUE, Integer.MAX_VALUE); }

public static final RandomGenerator<String> getStringGenerator() { return new RandomStringGenerator(""); }}

Page 22: Java Static Factory Methods

Advantages• RandomGenerators is just a noninstantiable utility class with nothing

else than static factory methods. Being on the same package as the different generators this class can effectively access and instantiate those classes. But here comes the interesting part.

• Note that the methods only return the RandomGenerator interface, and that’s all the clients need really.

• If they get a RandomGenerator<Integer> they know that they can call next() and get a random integer.

Page 23: Java Static Factory Methods

AdvantagesNot only can the class of an object returned by a public static factory method be nonpublic, but the class can vary from invocation to invocation depending on the values of the parameters to the static factory.

Any class that is a subtype of the declared return type is permissible. The class of the returned object can also vary from release to release for enhanced software maintainability and performance.

Page 24: Java Static Factory Methods

Advantages• A fourth advantage of static factory methods is that they reduce

the verbosity of creating parameterized type instances.

• Have you ever had to write code like this?

Map<String, List<String>> map = new HashMap<String,List<String>>();

Page 25: Java Static Factory Methods

Advantages• You are repeating the same parameters twice on the same line of

code. Wouldn’t it be nice if the right side of the assign could be inferred from the left side?

• Well, with static factories it can. The following code is taken from Guava’s Maps class:

public static <K, V> HashMap<K, V> newHashMap() { return new HashMap<K, V>();}

• So now our client code becomes:

Map<String, List<String>> map = Maps.newHashMap();

Page 26: Java Static Factory Methods

Advantages• Pretty nice, isn’t it? This capability is known as Type inference. It’s

worth mentioning that Java 7 introduced type inference through the use of the diamond operator. So if you’re using Java 7 you can write the previous example as:

Map<String, List<String>> map = new HashMap<>();

• Unfortunately, the standard collection implementations such as HashMap do not have factory methods as of release 1.6, but you can put these methods in your own utility class.

• More importantly, you can provide such static factories in your own parameterized classes.

Page 27: Java Static Factory Methods

DisadvantagesThe main disadvantage of static factories is that classes without public or protected constructors cannot be extended. But this might be actually a good thing in some cases because it encourages developers to favor composition over inheritance. (I am promise I will post about this interface-based framework in near future,

please don’t forget to following me at slideshare.)

• The same is true for nonpublic classes returned by public static factories. For example, it is impossible to subclass any of the convenience implementation classes in the Collections Framework.

• But I think this can be better seen by an our own example.

Page 28: Java Static Factory Methods

Disadvantages• Suppose you have a class called Person:

class Person { public static Person createWithFirstName(String firstName) { return new Person(firstName, null, null); } // etc. - more factory methods

// private constructor private Person(String firstName, String lastName, String nickname) { }

// useful method public String getDisplayName() { }}

Page 29: Java Static Factory Methods

Disadvantages• It's all good and dandy. But now you also need a class

called Programmer, and you suddenly realize the programmers are persons too!

• But all of a sudden, you can't just

class Programmer extends Person { }

• since Person doesn't have any public constructors.

• You can’t not subclassed which are not have public or protected constructor.

Page 30: Java Static Factory Methods

Summary (Preface)• In summary, static factory methods and public constructors both have

their uses, and it pays to understand their relative merits. Often static factories are preferable, so avoid the reflex to provide public constructors without first considering static factories.

Page 31: Java Static Factory Methods