Creational Patterns

Introduction

Creational patterns allow you to create objects while hiding the creational logic, which increase flexibility and code reusability, so you decide which objects need to be created for a particular case.

All Patterns

Factory

classDiagram
class Connection {
	<<interface>>
	connect()
}

class MySQLConnection {
	
}
MySQLConnection: +connect()

class OracleConnection {
	
}
OracleConnection: +connect()

class MongoDBConnection {
	
}
MongoDBConnection: +connect()

class ConnectionFactory {
	
}
ConnectionFactory: +getConnection(String connectionType) Connection

class Client {
	
}

Connection <|.. MySQLConnection : implements
Connection <|.. OracleConnection : implements
Connection <|.. MongoDBConnection : implements
MySQLConnection <-- ConnectionFactory : creates
OracleConnection <-- ConnectionFactory : creates
MongoDBConnection <-- ConnectionFactory : creates
ConnectionFactory <-- Client : ask for new object

It allows you to create objects without exposing the creation logic to the client.

This pattern is very convenient when you have many objects of the same type and you manipulate them frequently.

Implementation

  1. Create an interface for the target objects:

     public interface Connection {
         void connect();
     }
    
  2. Create concrete classes implementing the interface previously created:

     public class MySQLConnection implements Connection {
         @Override
         public void connect() {
             System.out.println("Connecting to MySQL...");
         }
     }    
    

    Other implementations…

  3. A factory class is defined:

     public class ConnectionFactory {
    
         public Connection getConnection(String connectionType) {
             switch (connectionType) {
                 case "mysql":
                     return new MySQLConnection();
                 case "mongodb":
                     return new MongoDBConnection();
                 case "oracle":
                     return new OracleConnection();
                 default:
                     return null;
             }
         }
     }
    
  4. The factory class is used by the client to create a concrete class given a name:

     public class Client {
    
         public static void main(String[] args) {
    
             ConnectionFactory connectionFactory = new ConnectionFactory();
             Connection mysqlConnection = connectionFactory.getConnection("mysql");
    
             if (mysqlConnection != null) {
                 mysqlConnection.connect();
             } else {
                 System.out.println("Please, provide a valid DB type");
             }
         }
     }
    

Abstract Factory

This pattern is a factory of factories and it allows you to create related objects without explicitly specifying their classes.

This pattern is very convenient when you have many objects of the same family and you manipulate them frequently.

Implementation

  1. Create an interface for the target objects:

     public interface Connection {
         void connect();
     }
    
  2. Create concrete classes implementing the interface previously created:

     public class MySQLAWSConnection implements Connection {
         @Override
         public void connect() {
             System.out.println("Connecting to MySQL...");
         }
     }    
    

  3. Create an interface to get factories of different family of objects:

     public interface ConnectionAbstractFactory {
         Connection getConnection(String connectionType);
     }
    
  4. Create factory classes extending the abstract factory class to generate object of concrete class given a name.

     public class AWSConnectionFactory implements ConnectionAbstractFactory {
         @Override
         public Connection getConnection(String connectionType) {
             switch (connectionType) {
                 case "mysql":
                     return new MySQLAWSConnection();
                 case "mongodb":
                     return new MongoDBAWSConnection();
                 case "oracle":
                     return new OracleAWSConnection();
                 default:
                     return null;
             }
         }
     }
    
     public class ConnectionFactory implements ConnectionAbstractFactory {
         @Override
         public Connection getConnection(String connectionType) {
             switch (connectionType) {
                 case "mysql":
                     return new MySQLConnection();
                 case "mongodb":
                     return new MongoDBConnection();
                 case "oracle":
                     return new OracleConnection();
                 default:
                     return null;
             }
         }
     }    
    
  5. Use the FactoryCreator to get the abstract factory class in order to get factories of concrete classes by passing names.

     public class Client {
    
         public static void main(String[] args) {
    
             ConnectionAbstractFactory awsConnectionFactory = FactoryCreator.getConnectionFactory(true);
             Connection mysqlAwsConnection = awsConnectionFactory.getConnection("mysql");
    
             if (mysqlAwsConnection != null) {
                 mysqlAwsConnection.connect();
             } else {
                 System.out.println("Please, provide a valid DB type");
             }
    
             ConnectionAbstractFactory regularConnectionFactory = FactoryCreator.getConnectionFactory(false);
             Connection mysqlRegularConnection = regularConnectionFactory.getConnection("mysql");
    
             if (mysqlRegularConnection != null) {
                 mysqlRegularConnection.connect();
             } else {
                 System.out.println("Please, provide a valid DB type");
             }
         }
     }
    

Singleton

It allows you to create a single instance of a class for the entire lifespan of your application, so you can make sure that a particular class is created only once.

It’s frequently used for logging classes, because a logging object usually needs to be used over and over again by many classes in the same application.

Singleton is a powerful pattern, but use it only when it is strictly necessary.

Implementation

classDiagram
class MySingleton{  
}

MySingleton : -MySingleton instance
MySingleton : -MySingleton()
MySingleton : +getInstance() MySingleton

MySingleton --> MySingleton

Singleton class implementations:

Singleton With Immutable Public Field

  1. Create singleton class:

     public class MySingleton {
    
         public static final MySingleton instance = new MySingleton();
    
         private int value;
    
         private MySingleton() {
    
         }
    
         public void setValue(int value) {
             this.value = value;
         }
    
         public int getValue() {
             return value;
         }
     }
    
  2. The client can get the object from the singleton class:

     MySingleton instance = SingletonWithPublicFinalField.instance;
    
     instance.setValue(100);
     System.out.println(instance.getValue());
    

Considerations: The constructor can be invoked reflectively. Therefore, there are ways to create more than one instantiation of the class.

// reflection concept to get constructor of a Singleton class.
Constructor<MySingleton> constructor = MySingleton.class.getDeclaredConstructor();
// change the accessibility of constructor for outside a class object creation.
constructor.setAccessible(true);

// creates first object of a class as constructor is accessible now.
MySingleton firstSingleton = constructor.newInstance();
firstSingleton.setValue(5);

// creates second object of a class as constructor is accessible now.
MySingleton secondSingleton = constructor.newInstance();
secondSingleton.setValue(10);
System.out.println(secondSingleton.getValue()); // value = 10
System.out.println(firstSingleton.getValue()); // value = 5

constructor.setAccessible(false);

Singleton With Factory Method

  1. Create singleton class:

     public class MySingleton {
    
         private static MySingleton instance = new MySingleton();
    
         private int value;
    
         private MySingleton() {
    
         }
    
         public static MySingleton getInstance(){
             return instance;
         }
    
         public void setValue(int value) {
             this.value = value;
         }
    
         public int getValue() {
             return value;
         }
     }
    
  2. The client can get the object from the singleton class:

     MySingleton mySingleton = SingletonWithFactoryMethod.getInstance();
    
     mySingleton.setValue(200);
     System.out.println(mySingleton.getValue());
    

Advantages:

Disadvantages:

Singleton With Lazy Initialization And Double Check Locking Pattern

This is similar to the previous singleton creation and it is only adding thread safety by using Double-Checked Locking Pattern.

  1. Create singleton class:

     public class MySingleton {
         private static volatile MySingleton instance;
    
         private MySingleton() {
    
         }
    
         public static MySingleton getInstance() {
             if (instance == null) { // 1st check
    
                 synchronized (MySingleton.class) {
    
                     if (instance == null) { // 2nd check
                         instance = new MySingleton();
                     }
                 }
             }
             return instance;
         }
     }
    
  2. The client can get the object from the singleton class:

     MySingleton mySingleton= LazyInitializationAndDoubleCheckLocking.getInstance();
    
     mySingleton.setValue(300);
     System.out.println(mySingleton.getValue());
    
Double-Checked Locking Pattern

Singleton With Enum

This is the preferred way.

  1. Create singleton class:

     public enum MySingleton {
    
         INSTANCE;
    
         private int value;
    
         public int getValue() {
             return value;
         }
    
         public void setValue(int value) {
             this.value = value;
         }
     }
    
  2. The client can get the object from the singleton enum:

     MySingleton mySingleton = EnumSingleton.INSTANCE;
    
     mySingleton.setValue(400);
     System.out.println(mySingleton.getValue());
    

Advantages:

Disadvantages:

Builder

// TODO

Prototype

// TODO