Software Design Patterns: Clean, Maintainable, and Flexible Code

Home » Programming » Java Programming » Software Design Patterns: Clean, Maintainable, and Flexible Code

I fell in love with Java programming after learning the software design patterns and Spring Boot framework. The Gang of Four(GoF) formulated 23 software design patterns. The software design patterns are the reusable solutions to the most frequently occurring problems in the software design. It is not a fixed set of algorithms that you can use. Rather, it provides a template/approach for solving a particular design problem. Each pattern within the 23 design patterns solves a specific design problem.

Categories of 23 Software Design Patterns

The 23 GoF patterns are categorized into three. They are creational, structural, and behavioral categories. The picture below separates each 23 patterns into specific categories.

Software Design Patterns
GoF 23 Software Design Patterns Categories

The creational category patterns deal with the creation of objects. The structural category deals with the composition of objects into bigger structures. Finally, the behavioral category deals with the interaction among the various objects in the software system. All the patterns contribute towards designing a modular system that is easy to maintain and extend without modifying the existing system. If at all with the minimum amount of modification.

Four Essential Elements of Design Patterns

In general, the pattern will have four essential elements. They are as follows

Pattern Name
Problem
Solution
Consequences

Describing Design Pattern

When describing each design pattern the most common terms that you come across are

Pattern Name – The name of the pattern.
Intent – What does the particular pattern do?
Structure – A UML diagram. In most cases, the class diagram represents different classes and interfaces.
Consequences – The pros and cons of applying the specific pattern.
Applicability – The situations in which the specific design pattern can be used.
Implementation – The sample implementation of the pattern in any programming language. In my case, I will use Java programming language.

The other terms you might come across are Also Known As, Participants, Collaborations, Known Uses, Related Patterns, etc… The participants are the components(classes and interfaces) of the structure.

Example: Observer pattern also known as publish-subscribe pattern

Let’s look into the Observer pattern and see what it does. What problem does it solve in the software design? How to implement it? We will use Java programming to implement it.

Intent

It models the publisher and subscriber communication. The subscribers are notified whenever the publisher publishes new content. It simulates the one-to-many dependency between the objects. The subscribers are dependent on the state of the publisher.

Structure

Observer Structure
Observer Pattern Class Diagram

Implementation

Let’s implement the Observer pattern for a news publishing company. There will be subscribers to the news company which is considered Observer. The news publishing company itself is the subject to which the Observer keeps an eye on. Whenever the news is published, all the subscribers are notified immediately of the news.

This is the helper class with which we can create news. It will be the collection of the articles.

import java.util.List;
import java.util.ArrayList;

//Article
public record  Article(String name, String body) {}

//News
public class News{
    List<Article> newsArticles = new ArrayList<>();

    public void addArticle(Article article){
        newsArticles.add(article);
    }

    public List<Article> getArticles(){
        return newsArticles;
    }

}

This is the Observer interface. It keeps an eye on the publisher.

//Observer Interface
public interface User{
    public void update(News news);
    public String getId();
}

This is the concrete implementation of the Observer. Whenever there is an update in the news, it calls the readNews() method to display all the articles inside the news.

//Concrete Observer
public class NewsLetterUser implements User{
    private String name;
    private String userId;
    private News news;

    public NewsLetterUser(String name, String userId){
        this.name = name;
        this.userId = userId;
    }

    public void update(News news){
        this.news = news;
        readNews();
    }

    public String getId(){
        return userId;
    }

    public void readNews(){
        System.out.println("User: " + name);
        System.out.println("Reading the Kunsel News");
        for(Article article: news.getArticles()){
            System.out.println("\t" + article);
        }
    }

}

This is the real subject interface. It will have the methods to subscribe, unsubscribe, notifySubscriber, and publish news.

//Subject Interface
public interface NewsLetter{
    public void subscribe(User user);
    public void unSubscribe(User user);
    public void notifySubscriber();  
    public void publish(News news);
}

This is the concrete implementation of the real subject. The Observers are interested in the change of the News object state. Whenever there is a new object of News, all the Observers will be notified of the new News object content. Kuensel is the news publisher.

import java.util.HashMap;

//Concrete Subject
class Kuensel implements NewsLetter{
    private HashMap<String, User> subscribers = new HashMap<>();
    private News news;
    
    public void subscribe(User user){
        subscribers.put(user.getId(), user);
    }
    public void unSubscribe(User user){
        subscribers.remove(user.getId());
    }

    public void notifySubscriber(){
        for(HashMap.Entry<String, User> user: subscribers.entrySet()){
            user.getValue().update(news);
        }
    }

    public void publish(News news){
        this.news = news;
        notifySubscriber();
    }

}

This is the Client, which interacts with the Observer pattern.

//Client
public class NewsLetterApp {
    public static void main(String[] args){
        //Lets build the Kunsel News First
        News kuenselNews = new News();
        kuenselNews.addArticle(new Article("Rising Temperature", "The global warming is causing the rise in the temperature"));
        kuenselNews.addArticle(new Article("Forest Fire", "The forest fire broke out in the capital"));

        //Real Subject
        Kuensel kuensel = new Kuensel();
        kuensel.subscribe(new NewsLetterUser("Sonam", "sonam123"));
        kuensel.subscribe(new NewsLetterUser("John", "john123"));

        //Lets publish the news
        kuensel.publish(kuenselNews); //Should see all the user in the console with the news

        kuensel.unSubscribe(new NewsLetterUser("John", "john123"));
        kuensel.publish(kuenselNews); // Publish same news, only Sonam should see the news
    }
}

Except for the News.java class, all the other classes represent the participants of the Observer pattern. In other words the components of the structure of the Observer pattern.

Output

User: Sonam
Reading the Kunsel News
        Article[name=Rising Temperature, body=The global warming is causing the rise in the temperature]
        Article[name=Forest Fire, body=The forest fire broke out in the capital]
User: John
Reading the Kunsel News
        Article[name=Rising Temperature, body=The global warming is causing the rise in the temperature]
        Article[name=Forest Fire, body=The forest fire broke out in the capital]
User: Sonam
Reading the Kunsel News
        Article[name=Rising Temperature, body=The global warming is causing the rise in the temperature]
        Article[name=Forest Fire, body=The forest fire broke out in the capital]

Consequences

Some of the consequences of applying the observer pattern are

It supports the layering of the software application. The Observer is the view and the subject is the data model in the typical MVC architecture. Whenever the data model changes, so does the view get updated.
It supports broadcast communication. The subject broadcasts to the list of Observers whenever the state of the subject changes which are of interest to the Observers.
It supports the open/close principle. You can add new types of subscribers without changing the code in the subject.

Conclusion

There is no hard rule stating when to use these 23 patterns of Gang of Four. It is up to the developer or the architect of the software system to decide. If you use it, definitely it gives you the power to write clean code. Which is modular and easy to maintain. Also, it can be very flexible to extend and reuse the code in the software system. When developing frameworks it is used most but not limited to it only. The Java Spring Boot framework uses lots of these patterns. After learning all the patterns you will find the Spring Boot framework easy to understand how it works under the hood.

1 thought on “Software Design Patterns: Clean, Maintainable, and Flexible Code”

  1. sugar defender complaints

    Your writing has a way of making even the most complex topics accessible and engaging. I’m constantly impressed by your ability to distill complicated concepts into easy-to-understand language.

Leave a Comment

Your email address will not be published. Required fields are marked *