A Beginner’s Guide to Design Patterns

Ever wondered what design patterns are? In this article, I'll explain why design patterns are important, and will provide some examples, in PHP, of when and why they should be used.

What are Design Patterns?

Design patterns are optimized, reusable solutions to the programming problems that we encounter every day. A design pattern is not a class or a library that we can simply plug into our system; it's much more than that. It is a template that has to be implemented in the correct situation. It's not language-specific either. A good design pattern should be implementable in most—if not all—languages, depending on the capabilities of the language. Most importantly, any design pattern can be a double-edged sword— if implemented in the wrong place, it can be disastrous and create many problems for you. However, implemented in the right place, at the right time, it can be your savior.

There are three basic kinds of design patterns:

structural

creational

behavioral

Structural patterns generally deal with relationships between entities, making it easier for these entities to work together.

Creational patterns provide instantiation mechanisms, making it easier to create objects in a way that suits the situation.

Behavioral patterns are used in communications between entities and make it easier and more flexible for these entities to communicate.

Why should we use them?

Design patterns are, by principle, well-thought out solutions to programming problems. Many programmers have encountered these problems before, and have used these 'solutions' to remedy them. If you encounter these problems, why recreate a solution when you can use an already proven answer?

Example

Let's imagine that you've been given the responsibility of creating a way to merge two classes which do two different things based on the situation. These two classes are heavily used by the existing system in different places, making it difficult to remove these two classes and change the existing code. To add to this, changing the existing code requires that you'll also need to test any changed code, since these sorts of edits, in a system which relies on different components, almost always introduce new bugs. Instead of doing this, you can implement a variation of the strategy pattern and adapter pattern, which can easily handle these types of scenarios.

Strategy Pattern

The strategy pattern is a behavioral design pattern that allows you to decide which course of action a program should take, based on a specific context during runtime. You encapsulate two different algorithms inside two classes, and decide at runtime which strategy you want to go with.

In our example above, the strategy is based on whatever the $context variable was at the time the class was instantiated. If you give it the context for class_one, it will use class_one, and vice versa.

Cute, but where can I use this?

Imagine that you're currently developing a class which can either update or create a new user record. It still needs the same inputs (name, address, mobile number, etc.), but, depending on a given situation, it has to use different functions when updating and creating. Now, you could probably just use an if-else to accomplish this, however, what if you need to use this class in a different place? In that case, you'll have to rewrite the same if-else statement all over again. Wouldn't it be easier to just specify your context?

Now, the "usual" strategy pattern involves encapsulating your algorithms inside another class, but in this case, another class would be wasteful. Remember that you don't have to follow the template exactly. Variations work as long as the concept remains the same, and it solves the problem.

Adapter Pattern

The adapter pattern is a structural design pattern that allows you to repurpose a class with a different interface, allowing it to be used by a system which uses different calling methods.

This also lets you alter some of the inputs being received from the client class, making it into something compatible with the adaptee's functions.

How can I use this?

Another term to reference an adapter class is a wrapper, which basically lets you "wrap" actions into a class and reuse these actions in the correct situations. A classic example might be when you're creating a domain class for table classes. Instead of calling the different table classes and calling up their functions one by one, you could encapsulate all of these methods into one method using an adapter class. This would not only allow you to reuse whatever action you want, it also keeps you from having to rewrite the code if you need to use the same action in a different place.

Factory Method Pattern

The factory method pattern is a creational design pattern which does exactly as it sounds: it's a class that acts as a factory of object instances.

The main goal of this pattern is to encapsulate the creational procedure that may span different classes into one single function. By providing the correct context to the factory method, it will be able to return the correct object.

When can I use this?

The best time to use the factory method pattern is when you have multiple different variations of a single entity. Let's say you have a button class; this class has different variations, such as ImageButton, InputButton and FlashButton. Depending on the place, you may need to create different buttons—this is where you can use a factory to create the buttons for you!

Decorator Pattern

The decorator pattern is a structural design pattern which enables us to add new or additional behavior to an object during runtime, depending on the situation.

The goal is to make it so that the extended functions can be applied to one specific instance, and, at the same time, still be able to create an original instance that doesn't have the new functions. It also allows for combining multiple decorators for one instance, so that you're not stuck with one decorator for each instance. This pattern is an alternative to subclassing, which refers to creating a class that inherits functionality from a parent class. As opposed to subclassing, which adds the behavior at compile time, "decorating" allows you to add new behavior during runtime, if the situation calls for it.

To implement the decorator pattern, we can follow these steps:

Subclass the original "Component" class into a "Decorator" class

In the Decorator class, add a Component pointer as a field

Pass a Component to the Decorator constructor to initialize the Component pointer

In the Decorator class, redirect all "Component" methods to the "Component" pointer, and

In the Decorator class, override any Component method(s) whose behavior needs to be modified

When can I use this?

The best place to use the decorator pattern is when you have an entity which needs to have new behavior only if the situation requires it. Let's say you have an HTML link element, a logout link, that you want to do slightly different things to based on the current page. For that, we can use the decorator pattern.

First, let's establish the different "decorations" we'll need.

If we're on the home page and logged in, have this link be wrapped in h2 tags

If we're on a different page and logged in, have this link be wrapped in underline tags

If we're logged in, have this link wrapped in strong tags

Once we've established our decorations, we can start programming them.

We can see here how we are able to combine multiple decorators if we need them. Since all the decorators use the __call magic function, we can still call the original function's methods. If we assume that we are currently inside the home page and logged in, the HTML output should be:

<strong><h2><a href="logout.php">Logout</a></h2></strong>

Singleton Pattern

The singleton design pattern is a creational design pattern which makes sure that you have one single instance of a particular class in the duration of your runtime, and provides a global point of access to the single instance.

This makes it easier to set up a point of "coordination" for other objects that use the singleton instance as well, since the singleton's variables will always be the same for anything that calls it.

When can I use this?

If you need to pass a specific instance from one class to another, you can use the singleton pattern to avoid having to pass the instance via constructor or argument. Imagine that you have created a Session class, which simulates the $_SESSION global array. Since this class will only need to be instantiated once, we can implement a singleton pattern like so:

By doing this, we can access our session instance from different parts of our code, even in different classes. This data will persist throughout all getInstance calls.

Conclusion

There are many more design patterns to study; in this article, I've only highlighted some of the more prominent ones that I use when programming. If you're interested in reading about the other design patterns, Wikipedia's Design Patterns page has a plethora of information. If that's not enough, you can always check out Design Patterns: Elements of Reusable Object-Oriented Software, which is considered to be one of the best design pattern books available.

One last thing: when you use these design patterns, always make sure that you're trying to solve the correct problem. As I mentioned previously, these design patterns are a double-edge sword: if used in the wrong context, they can potentially make things worse; but if used correctly, they become indispensable.