Design Patterns

Beknazar
5 min readMar 31, 2022

--

In this article, we will go over some common design patterns with Java. The design patterns are a common way of solving common problems.

  1. Singleton Pattern.
  2. Immutable Object Pattern.
  3. Builder Pattern.
  4. 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:

  1. Use a constructor to set all properties of the object.
  2. Mark all of the instance variables as private and final.
  3. Don’t define any setters methods, but provide getters(so we can work with this object).
  4. Don’t allow referenced mutable objects to be accessed directly.
  5. 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]
  1. We are using a public constructor to set all properties.
  2. All our instance variables are private and final.
  3. We don’t have setters so we cannot modify properties. Only getters are provided to read the properties of an object.
  4. 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.
  5. 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:

  1. We can easily add a new property to the Pizza object without changing the places where the Pizza objects were created with PizzaBuilder.
  2. 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.

--

--