Recently I was working on a Decorator pattern and struggling through PHP’s way of doing things. So naturally I thought why not take a look at how others have solved these same problems. The Gang of Four refer to the different classes and interfaces that make up a design pattern, as participants, and when I look at a design pattern, the first thing I do is to see how the developer handles the different participants. What I found was surprising—they left out chunks of a design pattern in their examples. Alternatively, they just did some kind of workaround that effectively made it work (run), but it was no longer a design pattern or had the advantages of a design pattern.
The Strategy with the Missing Context
The Strategy pattern decouples the algorithms from the Client by using a Context class. All of the requests for the algorithms (found in concrete Strategy classes) go through the Context to the Strategy interface and on the the implemented strategies in the form of concrete classes. However, in many of the PHP examples, they leave out the Context class and Strategy interface and go directly from an Object to concrete Strategies. In several examples, the code authors chose to ignore the interfaces and even the abstract classes and have fairly direct connections between concrete strategies and some kind of object. Figure 1 shows the kinds of UMLs that accompany these kinds of PHP design pattern implementations—if indeed they are implementations.
The authors of this kind of “explanation” of the Strategy pattern seem to think that the separation of the algorithms from the object is a matter of nothing more than taking the algorithms out of some object and using them independently of the main object. However, while that is an improvement on cramming everything into a single object (class), it is not a design pattern. Yes, it does add flexibility because more than one class can use the same concrete strategies. So, it’s a step away from single-class programming and even procedural programming. However, it is not a design pattern and it does not have the design pattern’s flexibility. The Context class uncouples the request from the strategy and without it, that concrete strategies are tightly linked to the “object”—whatever that may be.
The Decorator Without Abstractions
Every time I look at the Decorator’s class diagram, I shiver. It is the only design pattern with an abstract class that subclasses another abstract class. However, it does promote loose coupling and in its own way, an elegant design. However, in looking at every single implementation of the Decorator in PHP, something is missing. In one class diagram using the Unified Modeling Language (UML), not only did the author show only two participants (the main object) and the decorator object, but he shows the “decorator” implementing the main object.
For some reason, PHP programmers have adopted these abbreviated and inaccurate UMLs. My question is, Why? Why leave out participants that play key roles and just go on one’s merry way? They take the general idea and create something that lacks the structure that promotes loose coupling and then claim the results are design patterns. They’re not.
Where’s the Client?
One of the key elements in understanding design patterns is the role of the Client class. In many design patterns the Client is actually part of the design (e.g., Composite, Chain of Responsibility) or implied in the class diagram by a gray Client box with a specified relationship (e.g., Proxy, Iterator). The other design patterns that show no role in the class diagram for the Client are discussed in the GoF book. For example, the Strategy design pattern shows no role for the Client in the class diagram, but in discussing Strategy pattern collaborations, Gamma and his associates point out,
A context forwards requests from its clients to its strategy. Clients usually create and pass a ConcreteStrategy object to the context; thereafter, clients interact with the context exclusively. There is often a family of ConcreteStrategy classes for a client to choose from. (p. 317)
However, rarely have I seen a PHP example where there’s a Client class identified as such. Do requests emanate from a mysterious object and like magic turn an application into a design pattern? No. Requests come from a Client class, and these clients are discussed in every design pattern by the Gang of Four. Further, the class diagram either needs to show in the UML where the entry point/s is/are or explain it clearly in the write-up or other documentation. So, if I see no role for a Client, I usually conclude that the author may not have it exactly right.
Getting the Idea Right and Getting the Implemented Pattern Right
In reading the advantages of design patterns by some of the PHP design patterns authors, I was certain that they knew what they were doing. They seemed to understand the concept of re-usability, composition, and even programming to an interface instead of to an implementation—beautifully executed using code-hinting (the closest thing PHP has to data typing.)
However, following up on the right idea is a program with pieces missing. An easy counter-claim is that I’m being a purist, but that’s like saying that if the answer to 5 + 5 is 11, a purist is one who demands that the answer be 10. (After all 11 is close to the right answer.) This is not about a one-solution answer. Rather, it’s about putting all of the pieces of the puzzle together before claiming completion.
Put Up or Shut Up
It is true that I have not read every book or article (online or in print) on PHP design patterns, but from what I’ve seen in the books and online articles, most leave something out. It’s not that PHP programmers lack the right stuff—they don’t. Rather, it seems that some of the early examples of PHP design patterns got it wrong and others went on to follow up these wrong examples. While I’ve seen wrong examples of design patterns for every other language, including ActionScript 3.0, Java, C# and C++, PHP seems to have more than it’s share.
The goal is not to show how smart we are. Rather, in discussing what needs to be a part of a design pattern I’ve found that I have to think through exactly why each participant in a design pattern has to be there. For example, in the Strategy pattern, why do we need the Context class? Why can’t the Client make a request directly to the strategies, even going through the Strategy interface? After all, the Context is a concrete class; thus, it’s not the interface that we’re after. Including all of the participants in a design pattern example requires that each participant’s role be explained. Those explanations should help us better understand what the pattern accomplish, and we can better understand design patterns. That is the goal of this blog.
So now we’re stuck with coming up with good examples and better explanations of what design patterns are supposed to accomplish for the PHP programmer. Naturally, after being so critical of PHP patterns, we need to hold ourselves to those same standards. Given the rapid evolution of PHP from PHP 4 to the verge of PHP 6, one might think that it’s better to wait until PHP 6 is officially the new standard. However, in looking at PHP 6, you’ll find that a good PHP 5 program cast in a design pattern is easy to update (as are all programs using design patterns.) On this blog we’ll put up examples with the expectation that we’ll be examined and corrected where we need to be. The goal is to explore the value design patterns in PHP and get it right in doing so.
Copyright © 2010 William Sanders. All Rights Reserved.