PHP Patterns: The Observer Pattern
Introduction
The Observer pattern is perhaps most often encountered in traditional graphical user
interface desktop applications. It is an excellent way of ensuring that disparate
display components reflect changes at a system’s core. As we shall see, though, it
remains a powerful technique in a Web-oriented environment.
In this article I show you how to use the Observer pattern to build a flexible
broadcast-style relationship between a central component and the objects that
care about it.
First though, in preparation for a running example, I take a look at object
mocking a great technique for test-driving code.
Example Code and an Unexpected Bonus
In this article, as you might expect, I have cooked up an example to illustrate
my points. This is always a difficult task. The example needs to be credible
enough that a reader might imagine it out there in the real world. On the other
hand, one must sacrifice much that would be essential in code deployed in the
wild. The first to go is usually error checking. Nobody wants to plough through
thickets of try/catch clauses to get at the simple point buried within. The
same is true of incidental functionality. In an article about the way that
objects and classes interact, the process of talking to a database or of
parsing an XML document is often irrelevant. Such functionality can often
be replaced with simple print statements (‘update db’, ‘reading XML document’).
You might find a disclaimer of this kind in any one of hundreds of technical
articles. Tutorial code is geared towards understanding and not deployment.
In this case, though, it serves to illustrate a point. That is: interface
should outrank implementation in object-oriented programming. In designing
your code, you might try creating objects that do nothing at all but print
their intended actions. Focus on the classes in your system and their
relationships. Then focus on the operations they must define. Get that
right, and implementation code will often fall into place naturally.
Another important benefit you can derive from this approach lies in testing.
Unit testing itself is a topic for another article. Nevertheless, you should
consider strategies for building code that automates class testing. Of all
the problems you might encounter in testing a component, arguably the greatest
is context. An object rarely lives in isolation, and it may need to work with
others that speak to databases, the file system, or HTTP requests. How do
you reproduce these conditions in a test? One way is to ensure that an actual
HTTP request takes place, and a real database is on hand, stocked up with
valid data. This approach saddles you with the overhead of recreating a real
world context for the class you are testing, dragging your focus in the wrong direction.
If you’re coding to an interface, however, another option opens up. You can
create fake objects. If the code that talks to your database is nicely
encapsulated behind a clear interface, then there should be nothing to stop
you from creating a class that shares the same ancestry as your database class,
but serves up hard-coded data for testing purposes.
The example for this article concerns file uploads. A class, UploadManager,
works with UploadFile objects. Here is the UploadFile abstract
superclass and a simplified implementation:
|
The UploadFileImpl class is a simple wrapper around an element of
the $_FILES array which is automatically populated by the PHP engine
when an HTTP upload occurs. The class provides information about the uploaded file,
and supports moving it from its temporary holding location to a more permanent
home on the file system.
This class is simple and compact enough to use in examples, but it suffers from
one great drawback when used in tests and demonstrations. It requires a file upload
to have taken place. The fact that the UploadFileImpl class extends
an abstract superclass provides us with an opportunity. We can create a dummy
upload class that extends the same parent. Any client should be able to use this
interchangeably with the real thing. Such dummy classes are known as mocks.
Here is MockUploadFile:
|
Notice that this mock class is configurable. We can set key values, we can even cause
operations to fail if we want to. Because they can be set up to create error conditions,
such classes can act like spies or agents provocateurs in the enemy camp. We can send
them in to cause trouble, then sit back and watch the ensuing mayhem unfold.
Figure 1 shows the UploadFile type together with an unsuspecting client
class. The client is passed an UploadFile object and remains blissfully
unaware of the particular implementation with which it works. This is why it is
usually a good idea to pass objects around a system rather than have them instantiated
directly by the classes that use them. Of course objects must be instantiated somewhere,
and according to some logic. We will look at some of these strategies in a later article.

The Observer Pattern
Described by the Gang of Four (Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides)
in their seminal catalog, Design Patterns. Elements of Reusable Object-Oriented Software
(Addison Wesley, 1995), this pattern is a fantastic example of decoupling in action.
One of the great objectives of the object-oriented programmer is to create orthogonal
components. That means high cohesion (each component is bound up with itself and a core
purpose) and loose coupling (the components are as independent of their context as possible).
This buys us components that can be re-used easily, and perhaps more importantly it can
lead to systems that are flexible and less prone to bugs. Where by contrast the wider
system is allowed to take root in a component, so too does a web of interdependency. If
a component is too cozy with its context, it can’t easily be pulled away from it.
Furthermore, making a change in one part of a system can lead to unintended
consequences elsewhere.
We’ve all encountered systems that pepper SQL statements across all components. Such
promiscuous coding is tempting. It’s easier to query a database as and when you need
to than to devise a centralized strategy. The wages of sin, however, are toil and
error. A simple database schema change may require changes right across the system,
with the inevitable risk that an obscure statement or two is missed. Missed, that is,
until the morning you present your fantastic new application to a client or an investor.
Decoupling, then, is the process by which you disentangle components from their contexts,
and the Observer pattern is one strategy you should have in your decoupling toolbox.
Overview
The Observer pattern defines a mechanism by which components can opt-in to receive
messages when a target object (confusingly known as the subject) changes its
state. The subject need have no knowledge of the components ‘watching’ it for events,
beyond the fact that they are there and support an interface for notification.
The Problem
Imagine you are building a music community site that lets users upload their work
for sharing and assessment. For this purpose you have created the UploadFile
classes we have already seen, and now we need to manage the upload. There are some
legitimate issues that an UploadManager class should attend to. It should:
- check that a user hasn’t filled up her quota of space
- invoke
UploadFile::moveTo() - check for upload errors
- update the user’s disk space information
Here is an implementation:
|
The heart of this class is the processFile() method. It checks available
quota space, attempts to install the uploaded file, checks for errors, and updates
the user’s storage information.
Here is a simple User class that works with UploadManager:
|
As you can see, this class has been cut back to the bone so that it only supports file
storage functionality. We can query a User object to find out about its
quota, and the amount of storage it has in use and available. UploadManager
calls these methods to ensure that the current user has adequate space to store the
submitted clip.
Here’s some code that puts the classes through their paces:
|
We create a new User object with a storage quota of 4000 and pass it in to the
UploadManager constructor method. Finally we create a file object and invoke
UploadManager::processFile(). This sample simply outputs ‘OK’. We can make
things more interesting, though by poisoning our MockUploadFile object. This
sets the file size beyond the user’s quota:
|
Here we fake a file upload error:
|
So far the core classes in the example have remained reasonably focused upon their
own concerns. Perhaps UploadManager might usefully delegate a little
more to User, but that is an easy change to make at any time. Coupling
is loose, in that no component instantiates another, leaving ample opportunity for
class switching behind clear, well defined interfaces. Figure 2 illustrates the
usage relationships.
Now let’s introduce some flies into the ointment. The business group find more money
for the project and extend your brief. From now on, all uploads are to be logged.
Notification of failed transactions must be sent by mail to designated personnel.
Successful uploads should schedule a message to be sent via Web services to a third
party partner, but only while the partnership deal continues.
It is often new features that kill a design. UploadManager is certainly
a useful place to hang all these functions, but what does this spell for the system
as a whole? Logging might be something that you could expect business objects to
know about, but the ever-changing details of corporate partnership details may push
things a bit. It is your job to accommodate this logic, but how can you do it
flexibly? Here is an amended version of the class’s key methods:
|
As you can see, the UploadManager class has become mired by its context. It
is relying upon a constant, PARTNERSHIP_DEAL, as well as making some direct
instantiations. We could fix these problems by having objects passed in, or served up
by factory methods (more on these in future articles), but a core issue will remain:
UploadManager knows too much. The class has become site specific. We
couldn’t easily pick it up and drop it into another similar system because it now
relies explicitly upon too many classes and methods that are incidental to its core
purpose. Figure 3 illustrates the problem.
So, given that we need to inform these objects when an event occurs, how do we
remove the direct dependency of UploadManager upon all these classes?
[ continued in part 2 of PHP Patterns: The Observer Pattern ]
Categories: Uncategorized
Tags: Advanced, Articles, Design Patterns, Expert, Intermediate, PHP5


One comment to “PHP Patterns: The Observer Pattern”
September 2nd, 2007 at 12:38 am
Hey Matt,
I’m reading about patterns all day, some of the tutorials I’ve read are really good, but always people have to read 10 things to understand a single one.
The thing I didn’t get is why there is a composition relationship between the "UploadManager" class and the "User" one.
Some guys over here may not be familiar with UML as well, and I’m trying to understand that part:
…..
"Perhaps UploadManager might usefully delegate a little more to User"
….
In UML terms, the composition relationship, means that UploadManager is not "one piece" if there isn’t "User" as I tend to understand without checking the code, right?
Thanks!
Vladimir