In everyday life, we consistently face challenges and obstacles requiring us to think critically. As we encounter and solve problems, we build a skill set that allows us to traverse the world around us more easily. The field of software engineering is no different in that many challenges that arise during development are recurring situations that appear commonly throughout application design. Over time, developers have become familiar with these common scenarios and established standard implementation guidelines.
One such group of software engineers referred to as the Gang of Four wrote a book titled Design Patterns: Elements of Reusable Object-Oriented Software, which explores the capabilities and pitfalls of object-oriented programming. This publication has become a staple within the software development world, as it outlines standardized design patterns to aid developers in designing well-architected software. By familiarizing oneself with these design patterns, a developer will learn to apply streamlined solutions to common development challenges and become equipped with the necessary skills to build an architecture that is complete, maintainable, and supportive of future development.
Design patterns can generally be categorized into three groups: creational, structural, and behavioral. This series of readings provides a high-level overview of each group and examines a selection of design patterns from each. In addition, we will compare the patterns’ typical use cases and explore real-world applications through a mom-and-pop sandwich shop setting as a reference for how these principles can be applied in the software design and development processes.
Creational Design Patterns
The first design pattern group we will cover is creational, which highlights various methods for object instantiation. Creational patterns provide strategies to define the implementation of objects based on their use cases and provide separation between an entity’s creational logic and other functionality. When considering a creational design pattern for an object’s definition, it is essential to understand how the object and its properties are expected to behave. Characteristics to consider when choosing a creational design pattern are:
How many copies of the object will be created? (One? Many? None?)
How many attributes does the object have? How are these attributes used?
How unique is the object compared to other objects that already exist?
Will the object ever be used directly?
What is the desired default state for the entity?
As an introduction to creational design patterns, this reading will focus on two particular creational patterns: the singleton pattern and the factory pattern. In addition to these, there are a variety of other creational patterns, including the builder and prototype patterns, all of which increase flexibility and reusability of code through object creation strategies.
The Singleton Pattern
The singleton pattern restricts an object’s instantiation to a single instance, ensuring that only one copy of the object is created and accessible. Used for purposes like caching, logging, and thread pools, the singleton pattern provides a single global entity to be used system-wide, making tracking the object’s states and properties a breeze. In addition, the singleton pattern reduces the processing time that would otherwise be needed to create and handle multiple instances of an entity across the system.
The singleton pattern is a great design process when an entity’s properties and functionality apply globally across a system and when only one copy of the object is needed to run its code-logic and store its properties. To introduce the setting of our mom-and-pop sandwich shop, we can use the singleton pattern to define the restaurant:
Since one restaurant houses all employees and equipment, a single instance of the restaurant entity can be used globally in our system. The constructor is private to ensure that the entity cannot be initialized from another location. Our implementation of the RestaurantSingleton implements logic to allow the restaurant to open and close shop and track employees on duty.
The Factory Pattern
When multiple entities exist which extend the same superclass, the factory pattern can be used to instantiate objects of varying types. By implementing the factory pattern, developers can design a set of rules based on input parameters or other logic to determine the desired child class to instantiate. Found commonly in coding platforms’ low-level libraries such as Java’s javax.xml.parsers libraries and ADO.NET’s IDbCommand.CreateParameter functionality, the factory pattern is a staple when working with objects that extend a common entity.
In the context of our mom-and-pop shop, we can use the factory pattern to instantiate a menu item from the sandwich menu based on which item number a customer orders:
Assuming that each sandwich type extends the Sandwich class, the SandwichFactory will initialize and return a specific type of sandwich based on which menuItemNumber the customer chooses - #1 for PhillySandwich, #2 for HamAndCheeseSandwich, and #3 for VeggieSandwich.
In this article, we have introduced design patterns as a set of guidelines for common design challenges, and we have taken an in-depth look at a few creational patterns. We explored how the singleton and factory patterns can be applied to a mom-and-pop sandwich shop, with the restaurant implementing the singleton pattern and the sandwich menu implementing the factory pattern. Stay tuned for the next post in this series, where we will continue our exploration of design patterns by looking at structural patterns.