Decorating with External Data

      Comments Off on Decorating with External Data

While working on a project I realized one particular solution was a pretty good way to demonstrate the decorator design pattern together with some of PHP5’s features, including abstract classes, interfaces, type hinting, the final keyword and the visibility of properties and methods. This article is intended for those of you who, like myself, are moving from object-oriented programming, including some use of design patterns, in PHP4, to the more complete object model of PHP5. Part of the reason for writing it, was to get to grips with most of these concepts myself, I had also wanted to demonstrate an example of the use of the decorator that involved interaction with an external data source.

The Problem: Additional Pizza Toppings

You’re building an online ordering system for Joe, the owner of “Beaches Pizzeria”. So far, you’ve gotten your various products sorted into categories, like Pizza, Pasta, etc., then you’ve broken down the Pizza products into the different types, like Beaches Special, Seafood Supreme, Four Seasons, Tandoori, etc., and you’ve further broken those down into their sku’s (stock keeping units) like small, medium, large, etc.

So far, so good and you proudly take it along to the client:

“But what about the additional toppings?” Joe asks.
“Mmm… how about we add those to the list of sku’s?” you reply nervously.
“So you’re expecting me to list every single pizza, with every single combination, in one huge list which people have to choose from?!” snaps Joe.
“Ah, I… I erm…” you stammer.

At this point, you experience that cold panic brought on by suddenly discovering the time vacuum in your original estimate of the project!

The Solution: Decorate

To keep things simple, lets focus on “decorating” a Large “Beaches Special” Pizza. We’re going to grab the data from Beaches Pizzeria’s database using a query like so:

This returns the following rows:

The Code

You had already written an Sku class which included accessor methods like getId(), getName(), getCost() returning values like "21", "Beaches Special", "10.00", for our example pizza. It’s quickly obvious that each additional topping, which we will refer to as an sku variation, will need to have the same methods. To ensure this happens we are going to use an interface which will act as a sort of obligatory template, forcing any concrete classes to implement its methods:

Our Sku class can now implement this interface:

Now we can introduce our Decorator class which is going to implement the sku interface:

At this point you may have some questions about a few of the choices so far which I’ll pause to answer:

Why was an interface chosen for Sku_Interface?

If Sku was to extend an Sku_Abstract class it would no longer be able to extend any other class because PHP does not allow multiple inheritance. Since our aim is only to ensure that Sku includes a few methods, an interface serves as a gentler and more flexible option.

Why was an abstract chosen for Sku_Decorator?

First, Sku_Variation is unlikely to need to be extended by any other class so we can safely use an abstract rather than an interface.

Why do we need a separate decorator class at all?

In this instance we probably could just have Sku_Variation implement Sku_Interface directly, but by doing so we would be narrowing our options before we’re sure of what will be needed now and in future development. It’s also used, in this case, to discontinue the getStockLevel() method by making it final and empty, since it’s not needed by the sku variation and we don’t want to alter Sku_Interface.

With those answers hopefully making things a little clearer we can move onto the concrete class Sku_Variation. Note the way the object we intend to decorate is passed in through the constructor and the use of type hinting to ensure it is an instance of Sku_Interface. Our implemented methods getId(), getName() and getCost() can then reliably use the objects corresponding methods.

The Conclusion

All that is left is to put it all to work and get some output. First we’ll generate some simple info about the Sku object itself:

Then we will decorate it and show the cumulative effect on the id, name and price of the sku:

Finally, the resulting output is:

You can see how each sku variation “decorates” the previous one and yet, because we are drawing the data from an external source, we can avoid the complexity of having many small classes which can be a side-effect of using the decorator pattern. This is of course, just one example, but I find that reading different approaches to a design pattern can really help clarify it. Hopefully this will be one of those cases and I’d be interested to hear any examples, corrections or suggestions you may have.

Ingredients logo
Cooked up by Nick Lo | Ingredients