Introduction

Design patterns are typical solutions to commonly occurring problems in software design. They are like pre-made blueprints that you can customize to solve a recurring design problem in your code.

You can’t just find a pattern and copy it into your program, the way you can with off-the-shelf functions or libraries. The pattern is not a specific piece of code, but a general concept for solving a particular problem. You can follow the pattern details and implement a solution that suits the realities of your own program.

Patterns are often confused with algorithms, because both concepts describe typical solutions to some known problems. While an algorithm always defines a clear set of actions that can achieve some goal, a pattern is a more high-level description of a solution. The code of the same pattern applied to two different programs may be different.

Why Should I Learn Patterns?

The truth is that you might manage to work as a programmer for many years without knowing about a single pattern. A lot of people do just that. Even in that case, though, you might be implementing some patterns without even knowing it. So why would you spend time learning them?

  • Design patterns are a toolkit of tried and tested solutions to common problems in software design. Even if you never encounter these problems, knowing patterns is still useful because it teaches you how to solve all sorts of problems using principles of object-oriented design.
  • Classification of Patterns

    Design patterns differ by their complexity, level of detail and scale of applicability to the entire system being designed. I like the analogy to road construction: you can make an intersection safer by either installing some traffic lights or building an entire multi-level interchange with underground passages for pedestrians.

    The most basic and low-level patterns are often called idioms. They usually apply only to a single programming language.

    The most universal and high-level patterns are architectural patterns. Developers can implement these patterns in virtually any language. Unlike other patterns, they can be used to design the architecture of an entire application.

    In addition, all patterns can be categorized by their intent, or purpose. This book covers three main groups of patterns:

  • Creational patterns provide object creation mechanisms that increase flexibility and reuse of existing code.
  • Structural patterns explain how to assemble objects and classes into larger structures, while keeping these structures flexible and efficient.
  • Behavioral patterns take care of effective communication and the assignment of responsibilities between objects.
  • Patterns Catalog
    Factory Method

    Factory Method is a creational design pattern that provides an interface for creating objects in a superclass, but allows subclasses to alter the type of objects that will be created.

    PROBLEM

    Imagine that you’re creating a logistics management application. The first version of your app can only handle transportation by trucks, so the bulk of your code lives inside the Truck class.

    After a while, your app becomes pretty popular. Each day you receive dozens of requests from sea transportation companies to incorporate sea logistics into the app.

    Great news, right? But how about the code? At present, most of your code is coupled to the Truck class. Adding Ships into the app would require making changes to the entire codebase. Moreover, if later you decide to add another type of transportation to the app, you will probably need to make all of these changes again. As a result, you will end up with pretty nasty code, riddled with conditionals that switch the app’s behavior depending on the class of transportation objects.

    SOLUTION
    The Factory Method pattern suggests that you replace direct object construction calls (using the new operator) with calls to a special factory method. Don’t worry: the objects are still created via the new operator, but it’s being called from within the factory method. Objects returned by a factory method are often referred to as products.

    There’s a slight limitation though: subclasses may return different types of products only if these products have a common base class or interface. Also, the factory method in the base class should have its return type declared as this interface.

    PSEUDOCODE

    This example illustrates how the Factory Method can be used for creating cross-platform UI elements without coupling the client code to concrete UI classes.

    The base Dialog class uses different UI elements to render its window. Under various operating systems, these elements may look a little bit different, but they should still behave consistently. A button in Windows is still a button in Linux. When the factory method comes into play, you don’t need to rewrite the logic of the Dialog class for each operating system. If we declare a factory method that produces buttons inside the base Dialog class, we can later create a subclass that returns Windows-styled buttons from the factory method. The subclass then inherits most of the code from the base class, but, thanks to the factory method, can render Windows-looking buttons on the screen.

    For this pattern to work, the base Dialog class must work with abstract buttons: a base class or an interface that all concrete buttons follow. This way the code within Dialog remains functional, whichever type of buttons it works with.

    // The creator class declares the factory method that must // return an object of a product class. The creator's subclasses // usually provide the implementation of this method. class Dialog is // The creator may also provide some default implementation // of the factory method. abstract method createButton():Button method render() is Button okButton = createButton() okButton.onClick(closeDialog) okButton.render() class WindowsDialog extends Dialog is method createButton():Button is return new WindowsButton() class WebDialog extends Dialog is method createButton():Button is return new HTMLButton() interface Button is method render() method onClick(f) class WindowsButton implements Button is method render(a, b) is // Render a button in Windows style. method onClick(f) is // Bind a native OS click event. class HTMLButton implements Button is method render(a, b) is // Return an HTML representation of a button. method onClick(f) is // Bind a web browser click event. class Application is field dialog: Dialog method initialize() is config = readApplicationConfigFile() if (config.OS == "Windows") then dialog = new WindowsDialog() else if (config.OS == "Web") then dialog = new WebDialog() else throw new Exception("Error! Unknown operating system.") method main() is this.initialize() dialog.render()
    Singleton Design Pattern

    Singleton is a creational design pattern that lets you ensure that a class has only one instance, while providing a global access point to this instance.

    PROBLEM

    The Singleton pattern solves two problems at the same time, violating the Single Responsibility Principle:

    1. Ensure that a class has just a single instance. Why would anyone want to control how many instances a class has? The most common reason for this is to control access to some shared resource—for example, a database or a file.
    2. Here’s how it works: imagine that you created an object, but after a while decided to create a new one. Instead of receiving a fresh object, you’ll get the one you already created. Note that this behavior is impossible to implement with a regular constructor since a constructor call must always return a new object by design.

    3. Provide a global access point to that instance. Remember those global variables that you (all right, me) used to store some essential objects? While they’re very handy, they’re also very unsafe since any code can potentially overwrite the contents of those variables and crash the app.
    4. Just like a global variable, the Singleton pattern lets you access some object from anywhere in the program. However, it also p rotects that instance from being overwritten by other code. There’s another side to this problem: you don’t want the code that solves problem #1 to be scattered all over your program. It’s much better to have it within one class, especially if the rest of your code already depends on it.

      Nowadays, the Singleton pattern has become so popular that people may call something a singleton even if it solves just one of the listed problems.

    SOLUTION

    All implementations of the Singleton have these two steps in common:

  • Make the default constructor private, to prevent other objects from using the new operator with the Singleton class.
  • Create a static creation method that acts as a constructor. Under the hood, this method calls the private constructor to create an object and saves it in a static field. All following calls to this method return the cached object.
  • If your code has access to the Singleton class, then it’s able to call the Singleton’s static method. So whenever that method is called, the same object is always returned.

    PSEUDOCODE

    In this example, the database connection class acts as a Singleton. This class doesn’t have a public constructor, so the only way to get its object is to call the getInstance method. This method caches the first created object and returns it in all subsequent calls.

    class Database is private static field instance: Database private constructor Database() is // Some initialization code, such as the actual // connection to a database server. // ... public static method getInstance() is if (Database.instance == null) then acquireThreadLock() and then // Ensure that the instance hasn't yet been // initialized by another thread while this one // has been waiting for the lock's release. if (Database.instance == null) then Database.instance = new Database() return Database.instance public method query(sql) is // For instance, all database queries of an app go // through this method. Therefore, you can place // throttling or caching logic here. // ... class Application is method main() is Database foo = Database.getInstance() foo.query("SELECT ...") // ... Database bar = Database.getInstance() bar.query("SELECT ...") // The variable `bar` will contain the same object as // the variable `foo`.
    Observer Design Pattern

    Observer is a behavioral design pattern that lets you define a subscription mechanism to notify multiple objects about any events that happen to the object they’re observing.


    PROBLEM

    Imagine that you have two types of objects: a Customer and a Store. The customer is very interested in a particular brand of product (say, it’s a new model of the iPhone) which should become available in the store very soon.

    The customer could visit the store every day and check product availability. But while the product is still en route, most of these trips would be pointless.

    On the other hand, the store could send tons of emails (which might be considered spam) to all customers each time a new product becomes available. This would save some customers from endless trips to the store. At the same time, it’d upset other customers who aren’t interested in new products.

    It looks like we’ve got a conflict. Either the customer wastes time checking product availability or the store wastes resources notifying the wrong customers.

    SOLUTION

    The object that has some interesting state is often called subject, but since it’s also going to notify other objects about the changes to its state, we’ll call it publisher. All other objects that want to track changes to the publisher’s state are called subscribers.

    The Observer pattern suggests that you add a subscription mechanism to the publisher class so individual objects can subscribe to or unsubscribe from a stream of events coming from that publisher. Fear not! Everything isn’t as complicated as it sounds. In, reality, this mechanism consists of 1) an array field for storing a list of references to subscriber objects and 2) several public ,methods which allow adding subscribers to and removing them from that list.

    Now, whenever an important event happens to the publisher, it goes over its subscribers and calls the specific notification method on their objects.

    Real apps might have dozens of different subscriber classes that are interested in tracking events of the same publisher class. You wouldn’t want to couple the publisher to all of those classes. Besides, you might not even know about some of them beforehand if your publisher class is supposed to be used by other people.

    That’s why it’s crucial that all subscribers implement the same interface and that the publisher communicates with them only via that interface. This interface should declare the notification method along with a set of parameters that the publisher can use to pass some contextual data along with the notification.

    PSEUDOCODE

    In this example, the Observer pattern lets the text editor object notify other service objects about changes in its state.

    The list of subscribers is compiled dynamically: objects can start or stop listening to notifications at runtime, depending on the desired behavior of your app.

    In this implementation, the editor class doesn’t maintain the subscription list by itself. It delegates this job to the special centralized event dispatcher, letting any object act as a publisher.

    Adding new subscribers to the program doesn’t require changes to existing publisher classes, as long as they work with all subscribers through the same interface.

    class EventManager is private field listeners: hash map of event types and listeners method subscribe(eventType, listener) is listeners.add(eventType, listener) method unsubscribe(eventType, listener) is listeners.remove(eventType, listener) method notify(eventType, data) is foreach (listener in listeners.of(eventType)) do listener.update(data) // The concrete publisher contains real business logic that's // interesting for some subscribers. We could derive this class // from the base publisher, but that isn't always possible in // real life because the concrete publisher might already be a // subclass. In this case, you can patch the subscription logic // in with composition, as we did here. class Editor is public field events: EventManager private field file: File constructor Editor() is events = new EventManager() // Methods of business logic can notify subscribers about // changes. method openFile(path) is this.file = new File(path) events.notify("open", file.name) method saveFile() is file.write() events.notify("save", file.name) // Here's the subscriber interface. If your programming language // supports functional types, you can replace the whole // subscriber hierarchy with a set of functions. interface EventListener is method update(filename) // Concrete subscribers react to updates issued by the publisher // they are attached to. class LoggingListener implements EventListener is private field log: File private field message: string constructor LoggingListener(log_filename, message) is this.log = new File(log_filename) this.message = message method update(filename) is log.write(replace('%s',filename,message)) class EmailAlertsListener implements EventListener is private field email: string private field message: string constructor EmailAlertsListener(email, message) is this.email = email this.message = message method update(filename) is system.email(email, replace('%s',filename,message)) // An application can configure publishers and subscribers at // runtime. class Application is method config() is editor = new Editor() logger = new LoggingListener( "/path/to/log.txt", "Someone has opened the file: %s") editor.events.subscribe("open", logger) emailAlerts = new EmailAlertsListener( "admin@example.com", "Someone has changed the file: %s") editor.events.subscribe("save", emailAlerts)
    Visitor Design Pattern

    Visitor is a behavioral design pattern that lets you separate algorithms from the objects on which they operate.

    PROBLEM

    Imagine that your team develops an app which works with geographic information structured as one colossal graph. Each node of the graph may represent a complex entity such as a city, but also more granular things like industries,sightseeing areas, etc. The nodes are connected with others if there’s a road between the real objects that they represent. Under the hood, each node type is represented by its own class, while each specific node is an object.

    At some point, you got a task to implement exporting the graph into XML format. At first, the job seemed pretty straightforward. You planned to add an export method to each node class and then leverage recursion to go over each node of the graph, executing the export method. The solution was simple and elegant: thanks to polymorphism, you weren’t coupling the code which called the , export method to concrete classes of nodes.

    Unfortunately, the system architect refused to allow you to alter existing node classes. He said that the code was already in production and he didn’t want to risk breaking it because of a potential bug in your changes.

    Besides, he questioned whether it makes sense to have the XML export code within the node classes. The primary job of these classes was to work with geodata. The XML export behavior would look alien there.

    There was another reason for the refusal. It was highly likely that after this feature was implemented, someone from the marketing weird stuff. This would , force you to change those precious and fragile classes again.

    SOLUTION

    The Visitor pattern suggests that you place the new behavior into a separate class called visitor, instead of trying to integrate it into existing classes. The original object that had to perform the behavior is now passed to one of the visitor’s methods as an argument, providing the method access to all necessary data contained within the object.

    Now, what if that behavior can be executed over objects of different classes? For example, in our case with XML export, the actual implementation will probably be a little bit different across various node classes. Thus, the visitor class may define not one, but a set of methods, each of which could take arguments of different types, like this:

    class ExportVisitor implements Visitor is method doForCity(City c) { ... } method doForIndustry(Industry f) { ... } method doForSightSeeing(SightSeeing ss) { ... } // ...

    But how exactly would we call these methods, especially when dealing with the whole graph? These methods have different signatures, so we can’t use polymorphism. To pick a proper visitor method that’s able to process a given object, we’d need to check its class. Doesn’t this sound like a nightmare?

    foreach (Node node in graph) if (node instanceof City) exportVisitor.doForCity((City) node) if (node instanceof Industry) exportVisitor.doForIndustry((Industry) node) // ...

    You might ask, why don’t we use method overloading? That’s when you give all methods the same name, even if they support different sets of parameters. Unfortunately, even assuming that our programming language supports it at all (as Javaand C# do), it won’t method to execute. It’ll default to the method that takes an object of the base Node class.

    However, the Visitor pattern addresses this problem. It uses a technique calledDouble Dispatch, which helps to execute the proper method on an object without cumbersome conditionals. Instead of letting the client select a proper version of the method to call, how about we delegate this choice to objects we’re passing to the visitor as an argument? Since the objects know their own classes, they’ll be able to pick a proper method on the visitor less awkwardly. They “accept” a visitor and tell it what visiting method should be executed.

    // Client code foreach (Node node in graph) node.accept(exportVisitor) // City class City is method accept(Visitor v) is v.doForCity(this) // ... // Industry class Industry is method accept(Visitor v) is v.doForIndustry(this) // ...
    Strategy Design Pattern

    Strategy is a behavioral design pattern that lets you define a family of algorithms, put each of them into a separate class, and make their objects interchangeable.

    PROBLEM

    One day you decided to create a navigation app for casual travelers. The app was centered around a beautiful map which helped users quickly orient themselves in any city.

    One of the most requested features for the app was automatic route planning. A user should be able to enter an address and see the fastest route to that destination displayed on the map.

    The first version of the app could only build the routes over roads. People who traveled by car were bursting with joy. But apparently, not everybody likes to drive on their vacation. So with the next update, you added an option to build walking routes. Right after that, you added another option to let people use public transport in their routes.

    However, that was only the beginning. Later you planned to add route building for cyclists. And even later, another option for building routes through all of a city’s tourist attractions.

    While from a business perspective the app was a success, the technical part caused you many headaches. Each time you added a new routing algorithm, the main class of the navigator doubled in size. At some point, the beast became too hard to maintain. Any change to one of the algorithms, whether it was a simple bug fix or a slight adjustment of the street score, affected the whole class, increasing the chance of creating an error in already-working code. In addition, teamwork became inefficient. Your teammates, who had been hired right after the successful release, complain that they spend too much time resolving merge conflicts. Implementing a new feature requires you to change the same huge class, conflicting with the code produced by other people.

    SOLUTION

    The Strategy pattern suggests that you take a class that does something specific in a lot of different ways and extract all of these algorithms into separate classes called strategies.

    The original class, called context, must have a field for storing a reference to one of the strategies. The context delegates the work to a linked strategy object instead of executing it on its own.

    The context isn’t responsible for selecting an appropriate algorithm for the job. Instead, the client passes the desired strategy to the context. In fact, the context doesn’t know much about strategies. It works with all strategies through the same generic interface, which only exposes a single method for triggering the algorithm encapsulated within the selected strategy.

    This way the context becomes independent of concrete strategies, so you can add new algorithms or modify existing ones without changing the code of the context or other strategies.

    In our navigation app, each routing algorithm can be extracted to its own class with a single buildRoute method. The method accepts an origin and destination and returns a collection of the route’s checkpoints.

    Even though given the same arguments, each routing class might build a different route, the main navigator class doesn’t really care which algorithm is selected since its primary job is to render a set of checkpoints on the map. The class has a method for switching the active routing strategy, so its clients, such as the buttons in the user interface, can replace the currently selected routing behavior with another one.

    Reference