PHP Visitor Design Pattern I: The Single Dispatch

visitorTime to Add an Operation

I’ve always liked the Visitor Pattern, but it can appear somewhat daunting from the looks of the pattern’s class diagram. However, by easing into it, it’s fairly manageable and quite useful. In a nutshell, the Visitor allows developers to create programs that perform operations on elements in an object structure without changing the classes subject to the operation. In some respects this sounds a lot like the Decorator pattern but instead of adding properties, the Visitor pattern “visits” the structure with required operations.

Where the visitor comes into play is when you have a set of objects that share a common interface, but some–just some–need a method that does something not part of the interface, but it should not disrupt the interface or the related objects that do not need the method’s operation. In situations where added requirements crop up for extant structures, the Visitor is a welcomed guest.

An Element and a Pretend Visitor

To get started, instead of looking at the class diagram for the whole pattern, I want to take the Element interface and two concrete implementations of that interface as a point of departure. This particular set of concrete Element implementations create shapes using SVG graphics. One implementation creates a circle and the other a a square. Click the Play button to see what the program does and the Download button to view the files:
PlayDownload

A visitor object is one that adds an operation to an existing object without changing the object in the context of its interface. This first implementation assumes that the developer just wanted to make shapes and did not want to add fill color; so the fill color attribute of the SVG element has been left blank. (If no value is entered in the color attribute, it defaults to black–more on that later.)

In order to to show how a blank color is filled, the two shape-making implementations (Circle and Square) have a “pretend visitor.” The “visitor” is nothing but a private method that adds color. It is instructive insofar as it illustrates how to create an operation to add color to an existing method within a class.

First, take a look at the Element interface (IElement). It contains a constant with an immutable state and two methods; one for returning an object and the other the “pretend” visitor” supplies color to an otherwise colorless shape.

 
interface IElement
{
    //Constant for mutually shared code
    const SVG ="<svg width='2.2cm' height='2.2cm' viewBox='0 0 220 220'>";
    //Return object
    function showShape();
 
    //Pretend visitor
    function doColor();
}
?>

Next, two implementations of the IElement create Square and Circle classes. Importing the SVG element from the IElement interface (stored as a constant), each class simply returns the code for the requested shape.

//Square.php
<?php
class Square implements IElement
{
    public function showShape()
    {
        $squareShape= IElement::SVG . "<rect x='1' y='1' width='200' height='200' fill='{$this->doColor()}' stroke='blue' stroke-width='1' />";
        return $squareShape;
    }
 
    //Pretend visitor
    function doColor()
    {
        //pretent visitor red
        return "#b00";
    }
}
?>
 
//Circle.php
<?php
class Circle implements IElement
{
    public function showShape()
    {
        $circleShape= IElement::SVG . "<circle cx='110' cy='110' r='100' fill='{$this->doColor()}' stroke='blue' stroke-width='1' />";
        return $circleShape;
    }
 
    //Pretend visitor
    function doColor()
    {
        //pretent visitor green
        return "#0b0";
    }
}
?>

The pretend visitor is the doColor() method. It acts like a coloring operation that is coming from “somewhere else.” Subsequent posts examine how a real visitor works, but for now, just take a look at how an outside operation is used to establish color in the showShape() method. (Continue to learn about the roles of the Client and Single-Dispatch.)

The Client and Single Dispatch

First, look at the Client class to see how its request is a single dispatch:

<?php
//Client.php
error_reporting(E_ALL | E_STRICT);
ini_set("display_errors", 1);
// Autoload given function name.
function includeAll($className)
{
    include_once($className . '.php');
}
//Register
spl_autoload_register('includeAll');
 
//Client class begins here
class Client
{
    private static $shape;
    //client request
    public static function request()
    {
      self::$shape=$_POST['shape'];
      $dispatcher=new self::$shape();
      echo $dispatcher->showShape();
    } 
}
Client::request();
?>

Ignore the error reporting and autoload code for now, and focus on the Client class only. The HTML form sends a superglobal with a value for one of the two concrete Element classes (implementations of IElement), Circle or Square. A local variable $dispatcher (inside the methodrequest() method) instantiates the appropriate class and makes the request for showShape().

The best explanation of both single-dispatch and double-dispatch can be found on pp. 338-339 of Gang of Four’s book, Design Patterns: Elements of Reusable Object-Oriented Software. A single dispatch is determined by 1) name of the request (showShape()), and 2) the type of receiver (class instance—Circle or Square). Because the request is often polymorphic, as it is in showShape(), we only know what to expect by the receiver (class). A single dispatch to Circle::showShape returns a circle SVG image and a single dispatch to Square::showShape returns a square one.

The term receiver, in this context simply means the name of the class the requested method belongs to. The single-dispatch is one where the operation that gets executed depends on which request-receiver pair has been called. This may be a bit redundant, but single-dispatch is an important concept to understand in order to understand double-dispatch. In the next Visitor post on this blog, you will see how the Visitor pattern creates a double-dispatch, and in the meantime, look at the “pretend visitor” that does nothing more than return a color code and how it is incorporated in the showShape() method.

The HTML5 UI and a Reason to Avoid Conditional Statements

Most developers cannot imagine a coding environment without condimental statements. However, a good reason to avoid them lies in avoiding unnecessary operations and reducing clutter to ease code refactoring and reuse. None are used in this example.

One starting place to avoid using conditionals is in formatting the UI. If the requests are sent as class names, there’s no necessity for the Client to go through a set of stings and choose the one selected to be called. Instead, using the radio buttons named “shape” values as “Circle” and “Square” the superglobals passed the Client are all set to be instantiated:

    self::$shape=$_POST[‘shape’];
    $dispatcher=new self::$shape();

Everything is much smoother, and when it comes time to reuse, refactor or add another shape class, you don’t have to re-write all your code. For example, all that’s required to add a new shape object is to add a radio button with the name of the new class as a value (e.g., Triangle.) Then when the new class is added, it can be called without changing one line of code in the Client class, IElement interface or either concrete implementation of IElement. The following HTML document shows how easy it is:

<!DOCTYPE html>
<html>
<head>
    <link rel="stylesheet" type="text/css" href="visitor.css">
    <title>Visitor One Dispatch</title>
</head>
<body>
    <h3>Shape Dispatcher</h3>
    <form action="Client.php" method = "post" target = "feedback">
        <input type="radio" name="shape" value="Circle">&nbsp;Dispatch a circle<br />
        <input type="radio" name="shape" value="Square">&nbsp;Dispatch a square<br />
        <br /><input type="submit" name="sender" value="Do Dispatch">       
    </form>
    <iframe name="feedback" width="100" height="100">feedback</iframe>
</body>
</html>

The next installment of the Visitor Pattern examines the double-dispatch and how real visitors (not pretend ones) can be created with PHP.

Share

Copyright © 2015 William Sanders. All Rights Reserved.

0 Responses to “PHP Visitor Design Pattern I: The Single Dispatch”


  • No Comments

Leave a Reply