For those who have an extensive background in software engineering, design patterns should be familiar territory; however, there's an entire group of developers - especially in the web development community - who aren't necessarily familiar with design patterns (even though they've likely used them!).
In this series, we're going to take a look at design patterns, specifically in the context of WordPress, how they're useful, and some practical examples that we can use in our themes and plugins.
The ultimate goal of the series is to provide a solid definition of what design patterns are, why they're useful, how they're used in WordPress core, and then review two popular examples that we can easily employ in our own work.
Before we get to taking a look at some practical examples, let's define design patterns, and look at an example of how they are used in WordPress core.
Design Patterns Defined
For those of you who have never heard of or who have never used design patterns, it's important to understand what they are before we actually begin using them in our work.
Wikipedia provides the following definition:
A design pattern in architecture and computer science is a formal way of documenting a solution to a design problem in a particular field of expertise. An organized collection of design patterns that relate to a particular field is called a pattern language.
Perhaps a more simplified definition would be:
A pattern is a design that can be applied to a problem in a specific situation.
If that's still not clear, think of it this way:
- Whenever you're building a piece of software, you're likely to recognize that you're solving a problem that you've already solved before. As such, you know how to solve it.
- Naturally, the solution to the problem will be a slightly more generalized form that's applicable to how you've previously applied it.
- This generalized form of the solution can be considered the design pattern.
The general implementation and architecture will look exactly the same; however, the specifics of the implementation will naturally vary from project-to-project, but that's simply the nature of the beast.
In the upcoming sections and upcoming articles, we'll be taking a look at this in a bit more detail.
Design Patterns in WordPress
If you've done any type of WordPress development involving the hook system - that is, you've written entire plugins, themes, or even a simple function and taken advantage of the add_action
or add_filter
functions - then you've used design patterns.
WordPress uses what's called an event-driven design pattern. There are several variations of event-driven design patterns one of which we'll review momentarily, but the gist of the patterns are all the same:
- Part of the pattern implements what's known as a publisher
- Part of the pattern implements what's known as a subscriber
Generally speaking, the publisher broadcasts a message that something has happened to all objects that are subscribed to that particular publisher.
Another way of looking at this is that, in software, whenever something happens we say that an event is raised. Perhaps the most common place we see this in web development is in JavaScript with things such as the mouse being clicked, a key on the keyboard being pressed, or something similar.
We then write functions that handle those functions, and these functions are appropriately referred to as event handlers because they are responsible for handling the case when an event happens.
Not terribly complicated, right? Honestly, sometimes I think the terminology can be more confusing than the actual implementation.
So anyway, in the context of WordPress - or any web application, for that matter - events aren't limited to key presses or mouse clicks. Instead, it can happen during various parts of the page load lifecycle, when data is written to the database, when data is read to the database, and so on.
Ultimately, you can implement the pattern however you like so that you can provide hooks into which developers can register functions to fire as soon the event occurs.
This brings us full circle back to WordPress' architecture: Hooks are placed throughout the code such that we're able to register a function to fire whenever something occurs (that is, whenever an event happens).
A Look at an Event-Driven Architecture: The Observer Pattern
There are a number of event-driven design patterns, one of which is known as the Observer Pattern. This particular pattern is also known as the Publisher-Subscriber Pattern or, more concisely, Pub-Sub.
In the simplest implementation of this pattern, there is a single publisher that is responsible for broadcasting messages to one or many subscribers. The subscribers are responsible for registering themselves with the publisher, and then the publisher is responsible for sending a message or taking action on all of the subscribers.
A high-level diagram would look something like this:
From a code perspective, the Publisher needs three things:
- A way to maintain a list of the subscribers
- A way for the subscribers to register themselves
- A way to broadcast a message to all of the subscribers
Similarly, the Subscriber needs to be able to do two things:
- Register itself with the Publisher
- Optionally take action when the Publisher sends a message to it
There are a number of ways in which this can be implemented, but for all intents and purposes and to keep the example relatively simple, let's say that the Subscribers will register themselves with the Publisher with the Observer's register
method and the function accepts a reference to the Subscriber and each Subscriber has an update
method that the Publisher calls when broadcasting the message.
Publisher Code
class MyPublisher { /** The list of subscribers that are registered with this publisher */ private $subscribers; /** * Responsible for initializing the class and setting up the list of subscribers. */ public function __construct() { $this->subscribers = array(); } // end constructor /** * Adds the incoming subject to the list of registered subscribers * * @param array $subject The subject to add to the list of subscribers */ public function register( $subject ) { array_push( $this->subscribers, $subject ); } // end register_subscriber /** * Notifies all of the subscribers that something has happened by calling their `update` * method. */ public function notify_subscribers() { for ( $i = 0; $l < count( $this->subscribers ); $i++ ) { $current_subscriber = $this->subscribers[ $i ]; $current_subscriber->update(); } // end for } // end notify_subscribers } // end class
The code above is about as simple as we can make it:
For those who are more experienced with object-oriented techniques, then you'll likely see the need for creating a class interface for the Publisher, but that's outside the scope of this particular tutorial.
Remember, the purpose is to simply provide an example of what a simple observer may look like.
Subscribe Code
Creating a Publisher is really only half of the implementation. Remember, we have to have something that actually, you know, subscribes to the Publisher to take action whenever something happens.
This is where the aptly named Subscriber comes into play.
class MySubscriber { /** The publisher to which this class registers */ private $publisher; /** * Responsible for initializing the class and setting up a reference to the publisher */ public function __construct() { $this->publisher = new MyPublisher(); $this->publisher->register( $this ); } // end constructor /** * This is the method that the Publisher calls when it it broadcasts its message. */ public function update() { /** Implementation is based purely on however you'd like. */ } // end update } // end class
In short, this is it. Notice above that this implementation of the update
function isn't actually defined. That's because it gives us the ability to provide unique behavior to this specific instance.
But remember, there's a lot of code in WordPress core that is not object-oriented. Instead, it's procedural. As such, the implementation of a pattern like this varies a little bit.
For example, an analogy in WordPress would be something like this:
function my_custom_subscriber( $content ) { $content = 'This is my custom content.' . $content; return $content; } // end my_custom_subscriber add_action( 'the_content', 'my_custom_subscriber' );
Notice that the syntax is a bit different, but we're essentially doing a very similar thing:
- We have a subscribe function -
my_custom_subscriber
- and it's registered with thethe_content
event - When the
the_content
function fires, our custom function will fire.
Nothing too complicated, I hope.
One of the goals in this series is not only to provide a few examples of design patterns and how to implement them, but they are already in place in existing systems.
The Patterns We'll Examine
In addition to the event-driven pattern that we've examined above, we're also going to take a look at two patterns that are common, practical, and highly useful in our day-to-day work.
Specifically, we're going to take a look at the following patterns:
- Singleton Pattern. In object-oriented design, the Single Pattern ensures that only a single instance of a class is created. This is useful so that we don't accidentally create multiple instances maintaining their own sets of data ultimately giving conflicting results during a project's lifecycle.
- Simple Factory Pattern. If you have a collection of classes each of which are designed to handle a specific type of data (as opposed to have one large class do it), then the Simple Factory Pattern is useful for taking a look at the incoming data and then returning an instance of the proper class for processing the data.
Obviously, talking about software only goes so far without talking about diagrams and/or code so we'll be taking a look at both of those in the upcoming set of articles.
Conclusion
As you can see, the concept of design patterns isn't anything terribly complicated and there's a lot to be gained by using them in our work. Perhaps the greatest challenge that developers face is using design patterns for the sake of using design patterns.
Instead, it's important to recognize that there are certain situations in which design patterns are applicable. That is to say that there are certain problems for which design patterns are the perfect solution. Experience is arguably the best teacher for knowing when to use a design pattern and when not to use it.
In the following articles, hopefully we'll be able to cover enough territory to provide two solid examples of design patterns, when they're applicable, how to use them, and how they can help us in our future work.
Comments