3 Principles To Counter the Dark Side of Design Patterns

Son Hoang Kim
Vibentec-IT
Published in
9 min readJan 27, 2022

--

Design patterns have been "perceived" as obsolete in modern software engineering. Nevertheless, Design Patterns can be critically helpful if software developers have well understood and used them in the proper context and for the right reason.

Overall, this technique can generate a project:

· Easy to maintain

· Easy to upgrade

· Can be extended without making errors

Let's dive deep into designs Pattern to know how to use them handily!

Design pattern’s advantages
Design pattern’s advantages

What is meant by Design Patterns?

Design Patterns is a technique in object-oriented programming. It is pretty essential, and every programmer must know if they want to move to the next level in their field.

A design pattern is used frequently in OOP programming. Usually, you develop your own solution when you face a problem. However, it is not optimal in all situations. Design Patterns help you solve issues optimally, providing you with solutions in OOP programming.

Design Patterns are not specific for any languages at all. It can be done in most programming languages, such as Java, C#, Javascript, or any other programming language.

The history of Design Patterns

The idea of design patterns was first appeared in 1977 by Christopher Alexander. In 1987, Kent Beck and Ward Cunningham began experimenting with applying patterns to programming — specifically pattern languages — and presented their results at the OOPSLA conference that year. In the following years, many scientists keep working on this term. However, the time "Design patterns" became popular in computer science in 1994 after the book "Design Patterns — Elements of Reusable Object-Oriented Software" was published by four authors Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides. The book contains the origin of design patterns in programming and software. This book defined 23 patterns and divided them into three groups:

  • Creational Pattern (initialization group — including 5 patterns such as Factory Method, Abstract Factory, Builder, Prototype, Singleton). This kind provides a solution to create objects and hide the logic of its creation instead of creating the object directly using the new method. This group makes the program more flexible in deciding which objects should be created in the given situations.
  • Structural Pattern (structure group — including 7 patterns such as Adapter, Bridge, Composite, Decorator, Facade, Flyweight, and Proxy). This type is related to classes and object members. It is used to establish and define relationships between objects.
  • Behavioral Pattern (group of interactions/behaviors — including 11 patterns such as Interpreter, Template Method, Chain of Responsibility, Command, Iterator, Mediator, Memento, Observer, State, Strategy, and Visitor). This group is used in implementing the behavior of the object, the communication between the objects.

Below is the illustration about the relation of the 23 design patterns

Design Pattern relationships, from (Gamma et al., 1995)

In this article, I mainly introduce the very general view about them.

The overall groups

1. Creational Pattern

This group provides a solution to creating or hiding the logic instead of creating objects directly.

Creational patterns

Singleton

  • Strategy: To ensure a class has only one instance and provide a global access point.
  • Frequency of use: Medium-high.

Abstract Factory

  • Strategy: To provide an interface for creating objects without specifying the class or defining the class for each object.
  • Frequency of use: High.

Factory Method

  • Strategy: Define an interface to create an object but allow the subclass to decide which class to create. The factory method allows the subclass process initialization process.
  • Frequency of use: High.

Builders

  • Strategy: To decomposite the construction of a complex object so that multiple instants of the object can be created in the same construction process.
  • Frequency of use: Medium-low.

Prototypes

  • Strategy: Specify the type of objects to be created by using a prototype object. New objects are created by copying prototype objects.
  • Frequency of use: Medium.

2. Group Structural

This group defines and establishes the relationship between components, objects.

Structural Patterns

Adapters

  • Strategy: to deal with the compatibility issues between API, devices, etc., the Pattern allows changing the interface of a class to another interface that suits the user requirements.
  • Frequency of use: Medium-high.

Bridge

  • Strategy: Divide an abstraction into two parts but they can vary independently. The Pattern is useful when both the class and what it does change vary often. The class itself can be thought of as the abstraction and what the class can do like the implementation. This Pattern sometimes can be known as two layers of abstraction. It is often confused with the adapter pattern and be implemented with the adapter pattern.
  • Frequency of use: Medium.

Composite

  • Strategy: To organize objects in a tree hierarchy. The Pattern describes a group of objects that are treated the same way as a single instance of the same type of object. The term composite: "compose" objects into tree structures to represent part-whole hierarchies. Implementing the composite pattern lets clients treat individual objects and compositions uniformly.
  • Frequency of use: Medium-high.

Decorators

  • Strategy: To assign additional functionality to the object at runtime (dynamically).
  • Frequency of use: Medium.

Facade

  • Strategy: Providing a uniform interface for a set of interfaces in a "subsystem". It defines an interface above the existing ones to make the subsystem easier to use.
  • Frequency of use: High.

Flyweight

  • Strategy: To create common features to work efficiently on a large number of "small" objects (e.g. paragraphs, rows, columns, characters, etc.).
  • Frequency of use: Low.

Proxy

  • Strategy: To provide an object that represents another object to support or control access to that object. The replacement object is called a proxy.
  • Frequency of use: Medium-high.

3. Group behavioral

This group performs the interaction between components, objects.

Behavioral Patterns

Chain of Responsibility

  • Strategy: To consist of a source of command objects and a series of processing objects. Each processing object contains logic that defines the types of command objects that it can handle; the rest are passed to the next processing object in the chain. A mechanism also exists for adding new processing objects to the end of this chain.
  • Frequency of use: Medium-low.

Commands

  • Strategy: An object is used to encapsulate all information needed to perform an action or trigger an event at a later time. This information includes the method name, the object that owns the method, and values for the method parameters.
  • Frequency of use: Medium-high.

Interpreter

  • Strategy: Having a class for each symbol (terminal or nonterminal) in a specialized computer language. The syntax tree of a sentence in the language is an instance of the composite Pattern and is used to evaluate (interpret) the sentence for a client.
  • Frequency of use: Low.

Iterator

  • Strategy: An iterator is used to traverse a container and access the container's elements. The iterator pattern divides algorithms from containers; in some cases, algorithms are necessarily container-specific and thus cannot be divided.
  • Frequency of use: High.

Mediator

  • Strategy: To define an object to encapsulate the interaction between several objects.
  • Frequency of use: Medium-low.

Memento

  • Strategy: To modify and return the object's state without breaking the data.
  • Frequency of use: Low.

Observers

  • Strategy: To define a relation one-to-many between objects so that when an object changes state, all dependent objects are also changed.
  • Frequency of use: High.

State

  • Strategy: To allow an object to change its behavior when its internal state changes, giving the impression that the object's class is changed.
  • Frequency of use: Medium.

Strategy(also known as the policy pattern)

  • Strategy: To allow selecting an algorithm at runtime. Instead of implementing a single algorithm directly, code receives run-time instructions to decide which algorithms should be used.
  • Frequency of use: Medium-high.

Template method

  • Strategy: A method for superclass or an abstract superclass. It defines the skeleton of an operation in terms of a number of high-level steps. These steps are implemented by additional helper methods in the same class as the template method.
  • Frequency of use: Medium.

Visitor

  • Strategy: To allow working on the elements of a structure without changing the classes that define the structure.
  • Frequency of use: Low.

The dark sides of Design patterns

Design Pattern is meant to solve problems. However, the fact is that coin has two sides, and implementing the design pattern concept is as same as playing with a double-edged sword. Based on my experience, I would mention 3 big problems that I had chances to deal with:

  • Too complex and abstract
  • Requiring extensive knowledge
  • Causing an implementing performance problem

1. Practice makes perfect

The design pattern concept is super complex. It would be best to spend more time to genuinely understand the advantages and disadvantages of each Pattern and the most suitable case for them.

Back to the time when I first learned about design patterns, it was lucky for me to have chances to learn together with my friends. It brought me opportunities to have many different perspectives for every single Pattern.

The fact is that I also have read several technical blogs from senior developers. Putting all perspectives and knowledge together, I have practiced this technique as much as possible to gain more valuable experience.

2. The key leads to success: Flexibility — Creativity

The design pattern is not just complex but also abstract. Generally speaking, it is a template that is up to you to implement. Therefore, it requires flexibility while using any pattern.

According to my experience, I have made one critical mistake on the first time working with design patterns: Narrowing them down to some specific models. Leading to some troubles, my team struggled with debugging and implementing new features. Consequently, we had to spend more time and resources to reconstruct the whole project. As a matter of fact, each Pattern might be slightly different depending on the projects' purpose, features, and members' experience. In this case, an open mindset is significant in accepting the new and catching up with the rapid technology changes, including knowledge on this field.

Moreover, it does not matter how the patterns have changed or how good they can be, and we have to admit that design patterns are designed to solve general problems. For that reason, on top of everything, creativity in implementing is matters.

3. Simple is better

The biggest problem of applying the Design pattern to a project is that it can cause an implementing performance problem.

As mentioned above, the Design Pattern is abstract and complex. There is no need to make our projects more complicated by overusing them or using them without any plan. Even though there is always the case that most projects need to follow many patterns.

Hence, simple is better. Avoiding us from overusing or blind using, simplicity principle can shield us from disaster for debugging. This principle is about applying patterns when necessary, and this principle is also about organizing the project to make the system of many appear fewer and more precise. Moreover, this principle is also about documenting our project for the learning process of team members and future occasions.

Final Thought

Design Pattern is an essential and frequently discussed topic in the software industry. Based on decades of experience of many programmers, it provides solutions to help design safe and effective software, reduce bugs, and incur maintenance costs. Also, the Design pattern itself has disadvantages, but people still use it because its advantages outweigh its disadvantages.

--

--