Design Patterns.
Photos by Markus Spiske

Design Patterns.

Design patterns are a collection of standard solutions to solve software development design problems. Software engineers need to know how to use design patterns as essential tools. They can utilize design patterns to discover elegant solutions for commonly occurring challenges in software design, just as architects in building architecture learn to address design difficulties using established patterns. The efficiency, scalability, and readability of code are all improved by comprehending and utilizing these patterns.

The three categories that these patterns fall into are creational, behavioural, and structural. To keep things brief, we’ll define these categories and explore examples that fall into these categories over a series.

Creational Pattern: These patterns address procedures for creating objects. They assist in crafting objects in a way that makes sense for the scenario. The simplest method of creating objects may lead to problems with design or more complexity in a design. This issue is resolved by creational design patterns, which regulate the creation process. Some of the popular creational patterns include:

- Builder

- Factory

- Abstract Factory

- Singleton

- Prototype

Structural Pattern: The composition of classes and objects is central to structural patterns. They support the formation of complex structures with classes and objects. Structural patterns use inheritance to create interfaces and implementations. Several well-known patterns of structure include:

- Adapter

- Decorator

- Facade

Behavioral Pattern: a category of software design patterns that helps control how various system elements communicate and interact. Example includes:

- Observer

- Strategy

- State

- Iterator

We’ll start the series with one of the creational patterns: Singleton.

Singleton Pattern

Singleton pattern ensures that the instance of a class is instantiated once and provides global access to the instance. It is part of the creational design pattern category.

Motivation

When building a system, sometimes we want the system to have access to a shared resource, e.g. a database and a logging system. To make this work as intended, a single instance of an object or resource must exist at a time. Instantiating a constructor would not work because it returns a new instance of an object whenever it is called. Singleton pattern solves for us by ensuring that the regular constructor is called only once under the hood, and that is when it is being created for the first time.

Singleton pattern also provides global access to an object by making an object available everywhere in a program, which helps with;

1. Consistency: there should be at most one instance of a database in a system; if there is, it would further improve the level of consistency in the application's behaviour.

2. It helps to conserve resources

3. It also helps to control the means to access an object.

public class DataBaseService {

    public DataBaseService(){

    }
}        

Creating a DataBaseService class like the example above,

every time the class is instantiated, a new instance of the DatabaseService class is created, as shown below, which makes the class inconsistent for the intended use.

dataBase3: singleton.DataBaseService@135fbaa4        
dataBase4: singleton.DataBaseService@45ee12a7        


This is the implementation of a singleton pattern with respect to multithreaded environments like a Java program. This code below exposes a getInstance() method, which is called when we want to access the DataBaseService object, and it handles creating or providing an existing instance of the DataBaseService object. The private constructor in the class ensures the creation of an object using the regular constructor calling is controlled internally by the class. If dataBaseService is null, the class has not been created before and the regular constructor will be called.

public class DataBaseService {

    private static volatile DataBaseService dataBaseService = null;

    private DataBaseService() {

        if (dataBaseService != null) {

            throw  new RuntimeException("There can only be one instance of Database");

        }

    }

    public static DataBaseService getInstance() {

        if (dataBaseService == null){

        synchronized (DataBaseService.class) {

            if (dataBaseService == null) {

                dataBaseService = new DataBaseService();

            }

        }

    }

        return dataBaseService;

    }

}        

When we want to access the DataBaseService, we simply call the getInstance method, which creates or returns one instance of the class.

 DataBaseService dataBaseService1 = DataBaseService.getInstance();

        DataBaseService dataBaseService2 = DataBaseService.getInstance();

        System.out.println("dataBaseService1: "+ dataBaseService1);

        System.out.println("dataBaseService2: " + dataBaseService2);        

When the two instances are logged, it is evidently the same, which shows that our singleton pattern is properly implemented as shown below.

dataBaseService1: singleton.DataBaseService@135fbaa4

dataBaseService12: singleton.DataBaseService@135fbaa4        

Advantages

1. It is sure that there is only one instance of a class.

2. You can provide a global instance to a class.

Disadvantages

1. Violates single responsibility principles

Use cases

  1. Databases
  2. Logging system

Real-Life Examples

  1. Java Runtime Library
  2. Database connection on Android.

Conclusion

Singleton Pattern's approach to instance control makes it significant, but it's equally crucial to understand its strengths and weaknesses. Here's a link to check the full implementation.


Shout out to Markus Spiske for the cover photo.

要查看或添加评论,请登录

Iyanu Falaye的更多文章

  • Builder Pattern

    Builder Pattern

    Builder pattern is one of the creational design patterns. It is used to delegate the creation of complex objects.