Design Patterns

Singleton Design Pattern

If you need to instantiate just only one object of a particular class, use the Singleton pattern. Think of it as a “stage” and “performers”. There is only one stage and many performers that could use this stage. Think of the stage as one and only one object that you can instantiate. Singleton.

This is an example of a Singleton object oriented Design pattern:

  • Singleton has no public constructor. Create an empty private constructor.
  • Create a private static class variable and call it INSTANCE. This class variable can be shared among all objects of this class, but we are creating only one. Assign null to the INSTANCE class variable.
  • Create a public static method called getInstance() that method should return an INSTANCE class variable of the Stage type.
  • Check if the INSTANCE has a “null” value. If yes, create an object of the type Stage and assign it to the INSTANCE variable.
public class Stage {

    private static Stage INSTANCE = null;	
    
    private Stage() {}
	
    public synchronized static Stage getInstance() {
        if (INSTANCE == null) {
            INSTANCE = new Stage();
        }
        return INSTANCE;
    }
}

Now, each time you need an object of the Stage class just use the getInstance() method. If an object of this type is already exists, it will be returned. If not, a new object will be created.

public static void main(String[] args) {
    Stage stage = Stage.getInstance();
}

To prevent creating two or more singleton objects in multi-threading environment we have to put the synchronized keyword in the getInstance() method.

Factory Design Pattern

This pattern is useful if we want to use another class to create objects for us. The client delegates responsibility of knowing how to create objects properly to another class, which is called the factory class. The factory class returns objects that the client is expecting.

Let’s say we have a method that all our shuttles implement:

public interface Shuttle {
    public void launch();
}

Let’s have some shuttles. Shall we?

public class Discovery implements Shuttle {
    public void launch() {
        System.out.println("Discovery is launched!");
    }
}
public class Columbia implements Shuttle {
    public void launch() {
        System.out.println("Columbia is launched!");
    }	
}

Let’s create a shuttle factory:

public class ShuttleFactory {
    public Shuttle getShuttle(String shuttle) {
        if (shuttle.equals("Columbia")) {
            return new Columbia();
        } else if (shuttle.equals("Discovery")) {
           return new Discovery();
        }
        return null;
    }
}

To create and launch a specific shuttle, just send use it’s name as an argument:

public static void main(String[] args) {
    ShuttleFactory factory = new ShuttleFactory();
    Shuttle shuttle = factory.getShuttle("Columbia");
    shuttle.launch();
}

The factory design pattern is simple, but very powerful. We also may use Enums in order to remove logic statements from the shuttle factory.

Builder Design Pattern

The Builder pattern is one of the most popular Object Oriented Design Patterns.
It is used for creating object instances, when dealing with classes that have
large number of constructor arguments.

For example, you have an Employee class:

public Employee {
	private String firstName;
	private String lastName;
	private String phone;
	private int age;
}

Goal: Create an object of Employee class with only firstName and lastName fields.

Possible Solution: Create a constructor and pass only firstName and lastName arguments:

    public Employee(firstName, lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

Now, the goal was changed to create an object of Employee class with firstName, lastName
and the employee’s age.

Possible Solution: Create another constructor that overloads the initial one
and accepts all three attributes:

    public Employee(firstName, lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }
	
    public Employee(firstName, lastName, age) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.age = age;
    }

Now, how about to add all four attributes? A third construction has to be set, proving
that our approach is not effective. This is known as “Telescoping Constructor
Anti-pattern”.

Another Possible Solution: Create getters and setters for each attribute. All this
fields can be set when we create an object of the Employee class. But this is not
a thread safe solution. The state of this object is changing from one line to the
other.

Best approach is to use the Build Pattern:

public class Employee {
	private String firstName;
	private String lastName;
	private String phone;
	private int age;

	// Define a private! constructor and provide a Builder object as a
	// parameter.
	// Set only those fields to Employee object, that were passed with the
	// builder object of inner Builder class.
	private Employee(Builder builder) {
		this.firstName = builder.firstName;
		this.lastName = builder.lastName;
		this.phone = builder.phone;
		this.age = builder.age;
	}

	@Override
	public String toString() {
		return "Employee [firstName=" + firstName + ", lastName=" + 
			lastName + ", phone=" + phone + ", age=" + age + "]";
	}

	// Create a nested class that has the same fields as the outer class.
	public static class Builder {
		private String firstName;
		private String lastName;
		private String phone;
		private int age;

		// This method returns an instance of this inner class.
		public Employee build() {
			return new Employee(this);
		}

		public Builder firstName(String value) {
			this.firstName = value;
			return this;
		}
		
		public Builder lastName(String value) {
			this.lastName = value;
			return this;
		}
		
		public Builder phone(String value) {
			this.phone = value;
			return this;
		}
		
		public Builder age(int value) {
			this.age = value;
			return this;
		}

	}
}

Create any instance of the Employee class:

public static void main(String[] args) {
	Employee employee = new Employee.Builder()
		.firstName("James").build();
	System.out.println(employee);
}

// or

public static void main(String[] args) {
	Employee employee = new Employee.Builder()
		.firstName("James")
		.lastName("Bond").build();
	System.out.println(employee);
}

// or 

public static void main(String[] args) {
	Employee employee = new Employee.Builder()
		.firstName("James")
		.lastName("Bond")
		.phone("007").build();
	System.out.println(employee);
}
	
// or 

public static void main(String[] args) {
	Employee employee = new Employee.Builder()
		.firstName("James")
		.lastName("Bond")
		.phone("007")
		.age(55).build();
	System.out.println(employee);
}

Note, that the order of methods that set the fields is not important.

Also on GitHub