Item 1: Consider static factory methods instead of constructors - saurabhojha/Effective-java GitHub Wiki

This static factory method is not equivalent to the Factory design pattern.

A static factory method is a public method that simply returns the instance of the class.

For Example:

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

Advantages of static factory methods :

  1. Unlike constructors they have name. This helps in making the code more readable. This enables the user of such API call the correct method without checking the documentation, which is done in case of overloaded constructors.

In cases where a class seems to require multiple constructors with the same signature, replace the constructors with static factory methods and carefully chosen names to highlight their differences.

Sometimes we may have issues while creating overloaded constructors if they have same signature for different requirements.

Example: Suppose we have a Pixel class that uses rgb notation. Suppose we need to create 4 types of constructors:

  1. One that creates a pixel with mixture of these three colors.
  2. One that creates a pixel with only red color.
  3. One that creates a pixel with only green color.
  4. One that creates a pixel with only blue color.
class Pixel {
       private int r,g,b;
       //constructor to create a pixel with mixure of shades
       Pixel(int r,int g,int b) {
              this.r = r;
              this.g = g;
              this.b = b;
       }
       
       // constructor to create a pixel with only red.
       Pixel(int r) {
              this.r = r;
              this.g = 0;
              this.b = 0;
       }
       
       // constructor to create a pixel with only blue.
       //Error: Member with same signature already declared.
       Pixel(int g) {
              this.r = 0;
              this.g = g;
              this.b = 0;
       }

}

Since such an implementation would cause compilation error, we would think of overcoming this by using following designs:

One design could be to leave this implementation to the client. This is not a good idea.

Another solution could be overloading constructors with validation.

class Pixel {
       private int r,g,b;
       //constructor to create a pixel with mixure of shades
       Pixel(int r,int g,int b) {
              this.r = r;
              this.g = g;
              this.b = b;
       }
       // a mode variable to decide which color has to be assigned.
       Pixel(int shade,int mode) {
              if(mode==1) {
                     this(shade,0,0); //Red if mode is 1
              }
              else if(mode==2) {
                     this(0,shade,0); //Blue if mode is 2
              }
              else if(mode==3) {
                     this(0,0,shade); //Green if mode is 3
              }
              else {
                     this(shade,shade,shade); //Gray life 
              }
       }
}

Although this implementation works, there are a few issues.

  1. We have to handle the case of assigning gray color in case mode variable is invalidated.
  2. The client will have to go through documentation of the api to figure out which mode defines which color.

A solution can be implemented using static factory method.

class Pixel {
       private int r,g,b;
       //Private constructor to create a pixel
       private Pixel(int r,int g,int b) {
              this.r = r;
              this.g = g;
              this.b = b;
       }

       public static Pixel mixedPixel(int r,int g,int b) {
              return new Pixel(r,g,b);
       }

       public static Pixel redPixel(int r) {
              return new Pixel(r,0,0);
       }

       public static Pixel greenPixel(int g) {
              return new Pixel(0,g,0);
       }

       public static Pixel bluePixel(int b) {
              return new Pixel(0,0,b);
       }
}

Even though the number of methods have increased, the readability is greatly enhanced and the usage becomes easier.

  1. Unlike constructors, we do not need to return a new object every time a static factory method is called. This helps in cases when a equivalent objects are created often and are expensive to create. We can have one instantiation of the object which we can return every time a static factory method is called. If a constructor was called every time we needed an object, it would lead to duplicate objects.

Instance Controlled Classes: Classes with the ability to return limited number of instances over multiple invocations.

This advantage forms the basis of flyweight pattern. This also allows to guarantee that an instantiation can be singleton in nature.

public class singleInstance{
    //A sample singleton class.
    private static final singleInstance e = new singleInstance();

    private singleInstance(){}

    public static singleInstance getInstance(){
        return e;
    }
}

We have made the constructor private, which ensures it cannot be accessed without a public member function of the class. This ensures that the class has a tight control over object instantiation.

  1. Unlike constructors, a static factory method can return an instance of any subtype of their return type. This makes the code flexible. In essence, we can declare package-private classes that are hidden from the clients and then use static factory method to return instances of these subtypes from the superclass. This greatly reduces the no of methods/classes that a client might have to deal with.

Static factory method in java.util.EnumSet

Source: Stack Overflow

A static factory method:

  1. Have names (can be used instead of constructor overloading)

  2. Can be used to Cache instances. (flyweight/singleton)

  3. Can subtype. (use it to compact your Apis.)

  4. A fourth advantage of static factories is that the class of the returned object can vary from call to call, as a function of the input parameters. Any sub-type of the declared return type is permissible.

  5. This feature also helps us to return subtypes that are not written during the time of writing the factory static methods.

Disadvantages of static Factory Methods:

  1. You cannot extend a class without public or protected constructors.

Consider the example where we made the class Pixel.

class Pixel {
       private int r,g,b;
       //Private constructor to create a pixel
       private Pixel(int r,int g,int b) {
              this.r = r;
              this.g = g;
              this.b = b;
       }

       public static Pixel mixedPixel(int r,int g,int b) {
              return new Pixel(r,g,b);
       }

       public static Pixel redPixel(int r) {
              return new Pixel(r,0,0);
       }

       public static Pixel greenPixel(int g) {
              return new Pixel(0,g,0);
       }

       public static Pixel bluePixel(int b) {
              return new Pixel(0,0,b);
       }
}

Suppose we decide we need an alpha channel for this pixel now. In practice we must be able to do extend pixel and then add alpha for the alpha channel in the Pixel:

class AlphaPixel extends Pixel {
       int alpha;
       //...
}

However with the constructors of the Pixel class declared private, the AlphaPixel cannot extend the pixel Class now.

Arguably this can be a blessing in disguise because it encourages programmers to use composition instead of inheritance.

So we could do something like:

class Pixel {
       private int r,g,b;
       //Private constructor to create a pixel
       private Pixel(int r,int g,int b) {
              this.r = r;
              this.g = g;
              this.b = b;
       }

       public static Pixel mixedPixel(int r,int g,int b) {
              return new Pixel(r,g,b);
       }

       public static Pixel redPixel(int r) {
              return new Pixel(r,0,0);
       }

       public static Pixel greenPixel(int g) {
              return new Pixel(0,g,0);
       }

       public static Pixel bluePixel(int b) {
              return new Pixel(0,0,b);
       }
}
class Alpha {
       int alpha;
       Pixel pixel; // Composition of pixel in alpha.
}

Although this might not be the best use of composition, it gives an idea how it can overcome the problem of inheritance in certain cases.

  1. A second shortcoming of static factory methods is that they are hard for programmers to find. They might not stand out as much as constructors do in the documentation. One can follow the general naming conventions of static factory methods to overcome this problem.
⚠️ **GitHub.com Fallback** ⚠️