Design Pattern Classifications Part 1— Creational Pattern

Avelon Pang
CodeX
Published in
6 min readMay 21, 2021

--

With many unofficial and undocumented patterns out there that you might find useful in certain situations outside of the classic 23, how do you know which one to study or apply? A good place to start is by taking a look at the different classifications of design patterns. Although there are three main classifications, for the focus of this article we will be the creational design pattern. Together we will review what design patterns are, and the criteria used to categorize them before diving into the creational patterns in greater detail.

Design Patterns Review

In my previous article, we discussed that design patterns are proven solutions to commonly occurring problems in software design. You can think of them like pre-made blueprints that you can customize to solve a recurring design issue in your code. Not only are design patterns useful, but are considered best practices by experienced object-oriented software developers.

Categorization of Design Patterns

Before we dive right in, it is also important to consider the scope. The scope specifies whether the pattern applies primarily to class or to objects. Class patterns specify the relationship between classes and their subclasses, while object patterns deals with object relationships.

Since design patterns differ by their level of detail, complexity, and scale of applicability, it is important to categorize them by their intent or purpose. The purpose criteria reflects what the pattern does. The three main groups of patterns, are creational patterns, structural patterns and behavioral patterns. However, for the purpose of this article we will be focusing on the creational design pattern. The intent of the creational pattern is to provide object creation mechanisms that increase flexibility and reuse of existing code. The following discussion outlines the applicability and the pros and cons of five creational patterns.

Factory Method

This approach should be considered when you don’t know beforehand the exact types of dependencies of the objects your code should work with. Not only does it provide an interface for creating objects in a superclass, but also allows subclasses to alter the type of objects that will be created within it. This is a great way to provide users or your library or framework with a way to extend their internal components while saving system resources by using existing objects instead of rebuilding them each time.

Pros

  • Helps avoid tight coupling between the creator and the concrete products
  • Single Responsibility Principle — You can extract the product creation code into one place, making the code easier to support
  • Open/Closed Principle — where you can introduce new types of products into the program without breaking existing client code

Cons

  • Since you need to introduce a lot of new subclasses to implement this pattern, there is a high risk of the code becoming more complicated

Abstract Factory

This is a good design when your code needs to work with various families or related products, but depend on the concrete classes of those products for future extensibility. This is because it lets you produce families of related objects without specifying their concrete classes. In other words, the abstract factory design creates an instance of several families of classes. This can be used for creating cross-platform UI elements without coupling the client code to concrete UI classes, while keeping all created elements consistent with a selected operating system.

Pros

  • Avoids tight coupling between concrete products and client code
  • Products you’re getting from a factory are compatible with each other
  • Single Responsibility Principle
  • Open/Closed Principle

Cons

  • Potential for the code to become more complicated than it should be, since a lot of new interfaces and classes are introduced along with the pattern

Builder

The Builder pattern lets you build or construct complex objects step by step, allowing you to produce different types and representations of an object using the same construction code. If there is a complex nested object that requires a laborious step-by-step, this design allows you to avoid the headaches of that initialization by the builders. Builders help in creating complex composite trees because you can program its construction steps to work recursively. Ultimately, this design separates object construction from its representation.

Pros

  • You can construct objects step-by-step or defer construction steps recursively
  • Reuse the same construction code when building various representations of products
  • Single Responsibility Principle — You can isolate construction code from the business logic of the product

Cons

  • Increased complexity of the code as the pattern requires creating multiple new classes

Prototype

The purpose of this creational design pattern is to let you copy existing objects without making your code dependent on other classes. An object that supports cloning is called a prototype. This is a good approach to consider when your objects have dozens of fields and hundreds of possible configurations since cloning them might serve as an alternative to subclassing.

Pros

  • Cloning objects without coupling to their concrete classes
  • Get rid of repeated initialization code in favor of cloning pre-built prototypes
  • Ability to produce complex objects more conveniently
  • Get an alternative to inheritance when dealing with configuration presets for complex objects

Cons

  • Cloning complex objects that have circular references might be very tricky

Singleton

The singleton pattern lets you ensure that a class only has one instance, while providing a global access point to this instance. This is possible because all implementations of the Singleton make the default constructor private to prevent other objects from using the new operator with the Singleton class. This design should be used when a class in your program should have just a single instance available to all clients; for example, a single database object shared by different parts of the program. The Singleton pattern should also be used when you need stricter control over global variables.

Pros

  • Certainty that a class has only a single instance
  • Gain global access point to that instance
  • The singleton object is initialized only when it’s requested for the first time

Cons

  • Single Responsibility Principle violation
  • Potential for bad design when components of the program know too much about each other
  • May require special treatment in a multithreaded environment so that multiple threads won’t create a singleton object several times
  • Could be difficult to unit test the client code of the Singleton because many test frameworks rely on inheritance when producing mock objects
  • Promotion of tight coupling between classes in your application

Conclusion

Did you notice a common issue among these design patterns? Most of them were concerns of complexity. It is imperative to use these patterns only if they are useful and simplify code for you, not if they complicate your code. Now that you are familiar with the creational design patterns, you’ll have a better idea of which design to implement and when. To reiterate its importance, I encourage you to find out more about these design patterns as this was an introduction article and remember to first practice them in isolation before using a pattern in production code to limit code complexity or confusion.

Stay tuned for Design Pattern Classifications Part 2— Structural Pattern

Happy Coding!

--

--

Avelon Pang
CodeX

Full stack software developer with a passion for applying new technologies and a zest for technical problem solving. Bilingual in English and Mandarin.