Design patterns

  Windows IT Pro
Windows IT Library
  - Advertise        
Windows IT Pro Logo

  Home  |   Books  |   Chapters  |   Topics  |   Authors  |   Book Reviews  |   Whitepapers  |   About Us  |   Contact Us  |   ITTV  |   IT Jobs

search for  on    power search   help
 






Design patterns
View the book table of contents
Author: Dagfinn Reiersol
Published: June 2007
Copyright: 2007
Publisher: Manning Publications
 


7.4 NULL OBJECT

"Don’t turn on the dark light," my five-year-old son reproaches me when I turn out the lights in his room. The mental model revealed by this statement is an interesting and striking simplification of the physics involved. Instead of being opposites, he sees turning the light off and on as variations of the same process. There’s a bright and a dark light, and you can turn either one on. In object-oriented lingo, both the bright light class and the dark light class have a turnOn() operation or method. Like the dress() method of the Boy and Girl classes in chapter 4, this is polymorphism, a case of different actions being represented as basically the same.

In this section, we’ll see how Null Objects work, and then discover how to use them with the Strategy pattern.

7.4.1 Mixing dark and bright lights
A Null Object is the dark light of our object-oriented world. It looks like an ordinary object, but doesn’t do anything real. Its only task is to look like an ordinary object so you don’t have to write an if statement to distinguish between an object and a nonobject. Consider the following:
$user = UserFinder::findWithName('Zaphod Beeblebrox');
$user->disable();
If the UserFinder returns a non-object such as NULL or FALSE, PHP will scold us:
Fatal error: Call to a member function disable() on a non-object
in user.php on line 2
To avoid this, we need to add a conditional statement:
$user = UserFinder::findWithName('Zaphod Beeblebrox');
if (is_object($user))
    $user->disable();
But if $user is a Null Object that has disable() method, there is no need for a conditional test. So if the UserFinder returns a Null Object instead of a non-object, the error won’t happen.

A simple NullUser class could be implemented like this:
class NullUser implements User {
    public function disable() { }
    public function isNull() { return TRUE; }
}
The class is oversimplified, since it implements only one method that might be of real use in the corresponding user object: disable(). The idea is that the real user class, or classes, would also implement the interface called User. So, in practice, there would be many more methods.

7.4.2 Null Strategy objects
A slightly more advanced example might be a Null Strategy object. You have one object that’s configured with another object that decides much of its behavior, but in some cases the object does not need that behavior at all.

An alternative to using the Logging decorator shown earlier might be to build logging into the connection class itself (assuming we have control over it). The connection class would then contain a logger object to do the logging. The pertinent parts of such a connection class might look something like this:
class Connection {
    public function __construct($url,$logger) {
        $this->url = $url;
        $this->logger = $logger;
        // More initialization
        // ...
    }

    public function query($sql) {
        $this->logger->log('Query: '.$sql);

        // Run the query
        // ...
    }
}
Since this class accepts a logger object as input when it’s created, we can configure it with any logger object we please. And if we want to disable logging, we can pass it a null logger object:
$connection = new Connection(
    mysql://user:password@localhost/webdatabase,
    new NullLogger
);
A NullLogger class could be as simple as this:
class NullLogger implements Logger{
    public function log {}
}
Figure 7.6 shows the relationships between these classes. The interface may be represented formally using the interface keyword or an abstract class, or it may be implicit using duck typing as described in chapter 4.

The PEAR Log package has a Null logger class called Logger_null that is somewhat more sophisticated than the one we just saw.

Although a Null Object might do something such as return another Null Object, frequently it’s about doing nothing at all. The next pattern, Iterator, is about doing something several times.


7.5 ITERATOR

An iterator is an object whose job it is to iterate, usually returning elements one by one from some source. Iterators are popular. One reason may be that it’s easy to understand what they do, in a certain limited way, that is. It is relatively easy to see how they work and how to implement one. But it’s less obvious how and when they’re useful compared to the alternatives, such as stuffing data into a plain PHP array and using a foreach loop to iterate. In this section, we will see how iterators work, look at some good and bad reasons to use them, contrast them with plain arrays, and see how we can improve iterators further by using the Standard PHP Library (SPL).

7.5.1 How iterators work
An iterator is an object that allows you to get and process one element at a time. A while loop using an SPL (Standard PHP Library) iterator has this form:
while ($iterator->valid()) {
    $element = $iterator->current();
    // Process $element
    $iterator->next();
}
There are various interfaces for iterators, having different methods that do different things. However, there is some overlap. Above all, to be useful at all, every iterator needs some way of getting the next element and some way to signal when to stop. Table 7.1 compares the SPL iterator interface with the standard Java iterator interface and the interface used in the Gang of Four [Gang of Four] book.

7.5.2 Good reasons to use iterators

Three are three situations in which an iterator is undeniably useful in PHP:
  • When you use a package or library that returns an iterator
  • When there is no way to get all the elements of a collection in one call
  • When you want to process a potentially vast number of elements
In the first case, you have no choice but to use the iterator you’ve been given. Problem 3 will happen, for example, when you return data from a database table. A database table can easily contain millions of elements and gigabytes of data, so the alternative—reading all of them into an array—may consume far too much memory. (On the other hand, if you know the table is small, reading it into an array is perfectly feasible.)

Another example would be reading the results from a search engine. In this case, problems 2 and 3 might both be present: you have no way of getting all the results from the search engine without asking repeatedly, and if you did have a way of getting all of them, it would far too much to handle in a simple array.

In addition to the undeniably good reasons to use iterators, there are other reasons that may be questioned, because there are alternatives to using iterators. The most important alternative is using plain arrays. In the previous situations, using plain arrays is not a practical alternative. In other situations, they may be more suitable than iterators.

7.5.3 Iterators versus plain arrays

The general argument in favor of iterators is that they
  • Encapsulate iteration
  • Provide a uniform interface to it
Encapsulation means that the code that uses an iterator does not have to know the details of the process of iteration. The client code can live happily ignoring those details, whether they involve reading from a database, walking a data structure recursively, or generating random data.

The uniform interface means that iterators are pluggable. You can replace an iterator with a different one, and as long as the single elements are the same, the client code will not know the difference.

Both of these are advantages of using iterators. On the other hand, both advantages can be had by using plain arrays instead.

Consider the following example. We’ll assume we have a complex data structure such as a tree structure (this is an example that is sometimes used to explain iterators).
$structure = new VeryComplexDataStructure;
for($iterator = $structure->getIterator();
    $iterator->valid();
    $iterator->next()) {
    echo $iterator->current() . "\n";
}
The simpler way of doing it would be to return an array from the data structure instead of an iterator:
$structure = new VeryComplexDataStructure;
$array = $structure->getArray();
foreach ($array as $element) {
    echo $value . "\n";
}
It’s simpler and more readable; furthermore, the code required to return the array will typically be significantly simpler and leaner than the iterator code, mostly because there is no need to keep track of position as we walk the data structure, collecting elements into an array. As the Gang of Four say, "External iterators can be difficult to implement over recursive aggregate structures like those in the Composite pattern, because a position in the structure may span many levels of nested aggregates." In other words, iterating internally in the structure is easier.

In addition, PHP arrays have another significant advantage over iterators: you can use the large range of powerful array functions available in PHP to sort, filter, search, and otherwise process the elements of the array.

On the other hand, when we create an array from a data structure, we need to make a pass through that structure. In other words, we need to iterate through all the elements. Even though that iteration process is typically simpler than what an iterator does, it takes time. And the foreach loop is a second round of iteration, which also takes time. If the iterator is intelligently done, it won’t start iterating through the elements until you ask it to iterate. Also, when we extract the elements from the data structure into the array, the array will consume memory (unless the individual elements are references).

But these considerations are not likely to be important unless the number of elements is very large. The guideline, as always, is to avoid premature optimization (optimizing before you know you need to). And when you do need it, work on the things that contribute most to slow performance.

7.5.4 SPL iterators

The Standard PHP Library (SPL) is built into PHP 5. Its primary benefit—from a design point of view—is to allow us to use iterators in a foreach loop as if they were arrays. There are also a number of built-in iterator classes. For example, the built-in DirectoryIterator class lets us treat a directory as if it were an array of objects representing files. This code lists the files in the /usr/local/lib/php directory.
$iter = new DirectoryIterator('/usr/local/lib/php');
foreach($iter as $current) {
    echo $current->getFileName()."\n";
}
In chapter 19, we will see how to implement a decorator for a Mysqli result set to make it work as an SPL iterator.

7.5.5 How SPL helps us solve the iterator/array conflict

If you choose to use plain arrays to iterate, you might come across a case in which the volume of data increases to the point where you need to use an iterator instead. This might tempt you to use a complex iterator implementation over simple arrays when this is not really needed. With SPL, you have the choice of using plain arrays in most cases and changing them to iterators when and if that turns out to be necessary, since you can make your own iterator that will work with a foreach loop just like the ready-made iterator classes. In the VeryComplexDataStructure example, we can do something like this:
$structure = new VeryComplexDataStructure;
$iterator = $structure->getIterator();
foreach($iterator as $element) {
    echo $element . "\n";
}
As you can see, the foreach loop is exactly like the foreach loop that iterates over an array. The array has simply been replaced with an iterator. So if you start off by returning a plain array from the VeryComplexDataStructure, you can replace it with an iterator later without changing the foreach loop. There are two things to watch out for, though: you would need a variable name that’s adequate for both the array and the iterator, and you have to avoid processing the array with array functions, since these functions won’t work with the iterator.

The previous example has a hypothetical VeryComplexDataStructure class. The most common complex data structure in web programming is a tree structure. There is a pattern for tree structures as well; it’s called Composite.


7.6 COMPOSITE

Composite is one of the more obvious and useful design patterns. A Composite is typically an object-oriented way of representing a tree structure such as a hierarchical menu or a threaded discussion forum with replies to replies.

Still, sometimes the usefulness of a composite structure is not so obvious. The Composite pattern allows us to have any number of levels in a hierarchy. But sometimes the number of levels is fixed at two or three. Do we still want to make it a Composite, or do we make it less abstract? The question might be whether the Composite simplifies the code or makes it more complex. We obviously don’t want a Composite if a simple array is adequate. On the other hand, with three levels, a Composite is likely to be much more flexible than an array of arrays and simpler than an alternative objectoriented structure.

In this section, we’ll work with a hierarchical menu example. First, we’ll see how the tree structure can be represented as a Composite in UML diagrams. Then we’ll implement the most essential feature of a Composite structure: the ability to add child nodes to any node that’s not a leaf. (In this case, that means you can add submenus or menu options to any menu.) We’ll also implement a so-called fluent interface to make the Composite easier to use in programming. We’ll round off the implementation by using recursion to mark the path to a menu option. Finally, we’ll discuss the fact that the implementation could be more efficient.

7.6.1 Implementing a menu as a Composite

Let’s try an example: a menu for navigation on a web page such as the example in Figure 7.4. Even if we have only one set of menu headings, there are still implicitly three levels of menus, since the structure as a whole is a menu. This makes it a strong candidate for a Composite structure.

The menu has only what little functionality is needed to illustrate the Composite. We want the structure itself and the ability to mark the current menu option and the path to it. If we’ve chosen Events and then Movies, both Events and Movies will be shown with a style that distinguishes them from the rest of the menu, as shown in Figure 7.7.

First, let’s sketch the objects for the first two submenus of this menu. Figure 7.8 shows how it can be represented. Each menu has a set of menu or menu option objects stored in instance variables, or more likely, in one instance variable which is an array of objects. To represent the fact that some of the menus and menu options are marked, we have a simple Boolean (TRUE/ FALSE flag). In the HTML code, we will want to represent this as a CSS class, but we’re keeping the HTML representation out of this for now to keep it simple. Furthermore, each menu or menu option has a string for the label. And there is a menu object to represent the menu as a whole. Its label will not be shown on the web page, but it’s practical when we want to handle the menu.

A class diagram for the Composite class structure to represent menus and menu options is shown in Figure 7.9 It is quite a bit more abstract, but should be easier to grasp based on the previous illustration. Figure 7.8 is a snapshot of a particular set of object instances at a particular time; Figure 7.9 represents the class structure and the operations needed to generate the objects.

There are three different bits of functionality in this design:
  • Each menu and each menu option has a label, the text that is displayed on the web page.
  • The add() method of the Menu class is the one method that is absolutely required for generating a Composite tree structure.
  • The rest of the methods and attributes are necessary to make it possible to mark the current menu and menu option.
The two methods hasMenuOptionWithId() and markPathToMenuOption() are abstract in the MenuComponent class. This implies that they must exist in the Menu and MenuOption classes, even though they are not shown in these classes in the diagram.

The leftmost connection from Menu to MenuComponent implies the fact— which is clear in Figure 7.8 as well—that a Menu object can have any number of menu components (Menu or MenuOption objects).

Methods to get and set the attributes are not included in the illustration.

7.6.2 The basics

Moving on to the code, we will start with the MenuComponent class. This class expresses what’s similar between menus and menu options (Listing 7.9). Both menus and menu options need a label and the ability to be marked as current.


  1. mark() and isMarked() let us set and retrieve the state of being marked as current.


  2. We have simple accessors for the label. We will also set the label in the constructor, but we’re leaving that part of it to the child classes.


  3. markPathToMenuOption() will be the method for marking the path; both the menu object and the menu option object have to implement it. hasMenuOptionWithId() exists to support the marking operation.
To implement the most basic Composite structure, all we need is an add() method to add a child to a node (a menu or menu option in this case).
class Menu extends MenuComponent {
    protected $marked = FALSE;
    protected $label;
    private $children = array();

    public function __construct($label) {
        $this->label = $label;
    }

    public function add($child) {
        $this->children[] = $child;
    }
}
add() does not know or care whether the object being added is a menu or a menu option. We can build an arbitrarily complex structure with this alone:
$menu = new Menu('News');
$submenu = new Menu('Events');
$menu->add($submenu);
$submenu = new Menu('Concerts');
$menu->add($submenu);
7.6.3 A fluent interface

This reuse of temporary variables is rather ugly. Fortunately, it’s easy to achieve what’s known as a fluent interface:
$menu->add(new Menu('Events'))->add(new Menu('Concerts'));
All we have to do is return the child after adding it:
public function add($child) {
    $this->children[] = $child;
    return $child;
}
Or even simpler:
public function add($child) {
    return $this->children[] = $child;
}
A mentioned, this is all we need to build arbitrarily complex structures. In fact, if the menu option is able to store a link URL, we already have something that could possibly be useful in a real application.

7.6.4 Recursive processing

But we haven’t finished our study of the Composite pattern until we’ve tried using it for recursion. Our original requirement was to be able to mark the path to the currently selected menu option. To achieve that, we need to identify the menu option.

Let’s assume that the menu option has an ID, and that the HTTP request contains this ID. So we have the menu option ID and want to mark the path to the menu option with that ID. Unfortunately, the top node of our composite menu structure cannot tell us where the menu option with that ID is located.

We’ll do what might be the Simplest Thing That Could Possibly Work: search for it. The first step is to give any node in the structure the ability to tell us whether it contains that particular menu option. The Menu object can do that by iterating over its children and asking all of them whether they have the menu option. If one of them does, it returns TRUE, if none of them do, it returns FALSE:
class Menu extends MenuComponent...
    public function hasMenuOptionWithId($id) {
        foreach ($this->children as $child) {
            if ($child->hasMenuOptionWithId($id)) return TRUE;
        }
        return FALSE;
    }
}
The recursion has to end somewhere. Therefore, we need the equivalent method in the MenuOption class to do something different. It simply checks whether its ID is the one we are looking for, and returns TRUE if it is:
class MenuOption extends MenuComponent {
    protected $marked = FALSE;
    protected $label;
    private $id;

    public function __construct($label,$id) {
        $this->label = $label;
        $this->id = $id;
    }
    public function hasMenuOptionWithId($id) {
        return $id == $this->id;
    }
}
Now we’re ready to mark the path.
class Menu extends MenuComponent...
    public function markPathToMenuOption($id) {
        if (!$this->hasMenuOptionWithId($id)) return FALSE;
        $this->mark();
        foreach ($this->children as $child) {
            $child->markPathToMenuOption($id);
        }
    }
}
If this menu contains the menu option with the given ID, it marks itself and passes the task on to its children. Only the one child that contains the desired menu option will be marked.

The MenuOption class also has to implement the markPathToMenuOption() method. It’s quite simple:
class MenuOption extends MenuComponent...
    public function markPathToMenuOption($id) {
        if ($this->hasMenuOptionWithId($id)) $this->mark();
    }
}
But our traversal algorithm is not the most efficient one. We’re traversing parts of the tree repeatedly. Do we need to change that?

7.6.5 Is this inefficient?

We have deliberately sacrificed efficiency in favor of readability, since the data structure will never be very large. The implementation uses one method (hasMenuOptionWithId) to answer a question and another (markPathToMenuOption) to make a change. This is a good idea, which is why there is a refactoring to achieve this separation, called Separate Query from Modifier.

To make it slightly faster, we could have let the first method return the child that contains the menu option we’re searching for. That would have enabled us to avoid the second round of recursion. But it would also have made the intent of the has- MenuOptionWithId() method more complex and therefore harder to understand. It would have been premature optimization.

And this premature optimization would have involved a premature, low-quality decision. If we did want to optimize the algorithm, approaching optimization as a task in itself, we should be looking at more alternatives. For example, we could do the search, have it return a path to the menu option as a sequence of array indexes, and then follow the path. Or we could do it with no recursion at all if we kept a list of all menu options indexed by ID and added references back to the parents in the composite structure. Starting with the menu option, we could traverse the path up to the root node, marking the nodes along the way.

One thing the Composite pattern does is to hide the difference between one and many. The Composite, containing many elements, can have the same methods as a single element. Frequently, the client need not know the difference. In chapter 17, we will see how this works in the context of input validation. A validator object may have a validate() method that works the same way whether it is a simple validator or a complex one that applies several different criteria.

The Composite View pattern (which is the main subject of chapter 14) is related, though not as closely as you might think.


7.7 SUMMARY

While design principles are approximate guidelines, design patterns are more like specific recipes or blueprints; they cannot be used mindlessly. To apply them, we need to understand where, how, and why they’re useful. We need to look at context, consider alternatives, tweak the specifics, and use the object-oriented principles in our decision-making.

We have seen a small selection of design patterns. All of them are concerned with creating pluggable components. Strategy is the way to configure an object’s behavior by adding a pluggable component. Adapter takes a component that is not pluggable and makes it pluggable. Decorator adds features without impairing pluggability. Null Object is a component that does nothing, but can be substituted for another to prevent a behavior from happening without interfering with the smooth running of the system. Iterator is a pluggable repetition engine that can even be a replacement for an array. Composite is a way to plug more than one component into a socket that’s designed for just one.

In the next chapter, we will use date and time handling as a vehicle for making the context and the alternatives for design principles and patterns clearer.



Page: 1, 2



ADS BY GOOGLE SPONSORED LINKS FEATURED LINKS

Maximize your SharePoint Investment – 8 Cities
Discover best practices and tips for both architecting and administering SharePoint. Early Bird Price of $99 through Sept 15th.

Find a new job now on the all new IT Job Hound!
Search jobs, post your resume, and set up job e-mail alerts!

Master SharePoint with 3 eLearning Seminars
Learn how to build a better SharePoint infrastructure and enable powerful collaboration with MVPs Dan Holme and Michael Noel. Register today!

Top Tools for Virtualization Disaster Recovery & Replication
View this web seminar on August 14th to learn about two tools that will result in faster backup and restore with P2V disaster recovery.

SharePointConnections Conference Fall 2008
Don’t miss the premier event for Microsoft IT Professionals in Las Vegas, November 10-13. Register and book your room by August 25 and receive a FREE room night (based on a three night minimum stay).

VMworld 2008 - Sign Up Today!
Join your peers on September 15-18 at The Venetian Hotel in Las Vegas as VMware hosts VMworld 2008, the leading Virtualization event.



Entrust Unified Communications Certs
Secure Exchange 2007 and save 20%. Now through Sept. 2008.

Increase Application Performance
Free White Paper by Editor's Best winner, Texas Memory Systems.

Need to convert between XML, DBs, EDI, and Excel? Try MapForce free!
Drag & drop to transform between popular data formats – get results instantly or generate code.

Microsoft® Tech•Ed EMEA 2008 IT Professionals
Advance your thinking with new ideas and practical real-world solutions at Microsoft’s FIVE day technical infrastructure conference 3-7 Nov., 2008. Register before 26 September 2008 to save €300.

Order Your SQL Fundamentals CD Today!
Learn how to use SQL Server, understand Office integration techniques and dive into the essentials of SQL Express and Visual Basic with this free SQL Fundamentals CD.

Are You Really Compliant with Software Regulations?
View this web seminar that will help you with compliance best practices and check out a management solution to assure that you won’t be in jeopardy of an audit.

Virtualization Congress Oct. 14-16 in London
Don't miss Virtualization Congress, the premiere EMEA conference dedicated to hardware, OS and application virtualization. Oct. 14-16.
Windows IT Pro Home Register FAQ for Windows WinInfo News
Europe Edition About Us Contact Us/Customer Service Media Kit Affiliates / Licensing  
SQL Server Magazine Office & SharePoint Pro Windows Dev Pro IT Job Hound ITTV
IT Library Technical Resources Directory Connected Home Windows Excavator Windows SuperSite 
 
 Windows IT Pro is a Division of Penton Media Inc.
 Copyright © 2008 Penton Media, Inc., All rights reserved. Terms and Use | Privacy Statement | Reprints and Licensing