In this article, we will go over some common design patterns with Java. The design patterns are a common way of solving common problems.
- Singleton Pattern.
- Immutable Object Pattern.
- Builder Pattern.
- Factory Pattern.
Singleton Pattern
In some scenarios, we want to have only one instance of a particular class. That single instance should be easily accessible across the system. Singleton pattern simply restricts the creation of more than one instance of this type.
There are several ways to make class singleton.
The output of this program
Available balance: 25000.0
Available balance: 24750.0
---------
Available balance: 24750.0
Available balance: 19750.0
We are making the constructor private so there is no way to create objects from this class outside. But we are providing getInstance
method to share a single object that we created inside this class — instance
.
In the main method, we are working with two different references but there is no way to create two different objects because the only legal way to get an instance is via getInstance
method that returns the same object.
In this example, we initialized our object eagerly. We could do lazy initialization as well. Let’s say our class had some extra static methods to do some calculations that were not really related to the balance. In this case when we use Balance.calculate()
we are still initializing the balance object because it is eagerly initialized (meaning that it is getting initialized in the declaration) and if we do not use the balance object then we are just waisted this initialization.
Lazy Initialization is the way to initialize when we need this object.
In this example, the instance will be initialized only if getInstance
method is invoked, but the class is still singleton and only one instance will available in the system.
Immutable Objects Pattern
The objects work with references in Java. We pass around the reference of object and in some scenarios, it can be a little messy. The immutable object pattern allows us to create an object that is not changeable. The state(properties) of the object will be always the same and the only way to change the object is to create a new one with a different state(properties). The immutable objects are inherently thread-safe. Sometimes, immutable objects are referred to as simple objects.
String
is an immutable object. Once we created our String with value, there is no way I can change this original String. The only way is to create a new one.
String str = "apple";
System.out.println(str.toUpperCase()); // APPLE
System.out.println(str); // apple // only way to change is to reassing with new object
str = str.toUpperCase();
System.out.println(str);
There are different ways of making a class immutable. This is a common way of doing so:
- Use a constructor to set all properties of the object.
- Mark all of the instance variables as
private
andfinal
. - Don’t define any setters methods, but provide getters(so we can work with this object).
- Don’t allow referenced mutable objects to be accessed directly.
- Prevent methods from being overridden by making a class final or making all methods final.
the output from this program
Veggie
15.99
[broccoli, squash, tomatoes]
---------
Veggie
18.990000000000002
[broccoli, squash, tomatoes]
- We are using a public constructor to set all properties.
- All our instance variables are
private
andfinal
. - We don’t have setters so we cannot modify properties. Only getters are provided to read the properties of an object.
- This one is important and easy to miss. If the object property is a mutable object then we have to return and set copies, otherwise, the client code can get direct access to the property and change it.
- Our class is final so it cannot have child classes hence the methods cannot be overridden.
Builder Pattern
We will take a look builder pattern together with the pattern of the immutable object. When the immutable object grows the constructor arguments should grow as well. If an object has 30–40 properties then the constructor should have the same number of arguments and new properties will require change for this constructor and if it was used in many places it becomes hard to manage. Also, sometimes we don’t want to assign all values at once with one constructor, might be some values are optional. We could create overloaded constructors but over time it makes our class hard to manage. In fact, this problem is known as a telescoping constructor anti-pattern (the solution for the problem that seems to be a good solution at that time, however, over time, it makes the problem more complex).
The builder pattern is a class with the setters that are used with method chaining to build object properties. And usually, the builder classes will generate an immutable class with the final build method, although it can be used with regular mutable classes as well.
The output of this program
Veggie
15.99
[broccoli, squash, tomatoes]
11
4.0
null
-----------------
Chicago Pizza
21.5
[]
The advantages of builder here:
- We can easily add a new property to the Pizza object without changing the places where the Pizza objects were created with PizzaBuilder.
- We can create a Pizza object with only the required for us properties without maintaining multiple overloaded constructors.
Factory Pattern
The idea of a factory pattern is to create an object based on a set of input parameters. Let’s say we get to know what object we need to use during the runtime only. We can use the factory pattern to give us the correct object during runtime based on some argument. Of course, it goes hand to hand with polymorphism in java.
Please take my Java Course for video lectures.This article is part of the series of articles to learn Java programming language from Tech Lead Academy:Introduction to programming
OS, File, and File System
Working with terminal
Welcome to Java Programming Language
Variables and Primitives in Java
Convert String to numeric data type
Input from the terminal in Java
Methods with Java
Java Math Operators and special operators
Conditional branching in Java
Switch statement in Java
Ternary operator in Java
Enum in Java
String class and its methods in Java
Loops in Java
Access modifiers in Java
Static keyword in Java
The final keyword in Java
Class and Object in Java
Object-Oriented Programming in Java
OOP: Encapsulation in Java
OOP: Inheritance in Java
OOP: Abstraction in Java
OOP: Polymorphism in Java
The method Overriding vs Overloading in Java
Array in Java
Data Structures with Java
Collection framework in Java
ArrayList in Java
Set in Java
Map in Java
Date and Time in Java
Exception in Java
How to work with files in Java
Design Patterns
Generics in Java
Multithreading in java
Annotations in Java
Reflection in Java
Reflection & Annotations - The Powerful Combination
Run terminal commands from Java
Lambda in Java
Unit Testing in Java
Big O Notation for coding interviews
Top Java coding interview questions for SDET