Chapter 12. The Flexibility of the Strategy Design Pattern

Victorious warriors win first and then go to war, while defeated warriors go to war first and then seek to win.

In preparing for battle I have always found that plans are useless, but planning is indispensable.

All I had done was to improve on their strategy, and it was the beginning of a very important lesson in life—that anytime you find someone more successful than you are, especially when you’re both engaged in the same business—you know they’re doing something that you aren’t.

One of the ongoing tasks in using PHP with MySQL is writing algorithms for the different kinds of requests made of a MySQL application. Typical requests include creating tables or entering, selecting, changing, and deleting data. The algorithms for these different requests are simple or complex depending on both the complexity of the request and of the table.

One of the main principles of design patterns is to encapsulate what varies. With several different algorithms for different kinds of requests sent to a PHP class that handles these MySQL requests, the variation is clearly the algorithms. The variations may be small or great, but using the Strategy design pattern, we can greatly simplify the process.

Generally, with design patterns, the question is “What causes redesign?” Then, we proceed to avoid those things that force redesign. But what if we instead think of a way to make changes without redesign? By encapsulating what varies, programmers first decide what will vary in a program and then encapsulate those features. When a design requires change, the encapsulated elements can be changed without affecting the rest of the system. Since different MySQL tasks require different algorithms, the algorithms (tasks) can be encapsulated, and the Strategy design pattern applied.

To get started, take a look at Figure 12-1. It shows the class diagram for the Strategy design pattern.

Now go back to Chapter 10 and look at Figure 10-1. The pattern participants are organized in a very similar fashion to what you see in Figure 12-1. The Context participant has an aggregate relationship with an interface in both designs. With the State pattern it is the State interface, and with the Strategy pattern it is the Strategy interface. Otherwise they appear identical.

To understand the differences, you need to see how the different Context participants behave in relationship to the Strategy and State interfaces and their concrete implementations. Table 12-1 summarizes these differences.

As you saw in Chapter 10, the Context kept a variable holding the current concrete state. The concrete states provide methods for going to another state from the current state as recorded in a Context variable.

However, the Context participant in the Strategy pattern has no ongoing record of the current strategy in use. It has no reason to because unlike changing states, generally changing algorithms is not dependent on the current one in use. Obviously, you have situations where one algorithm should be used before another, such as inserting data into a table before attempting to retrieve it. Nevertheless, that does not prevent the algorithm from being used to attempt to retrieve data from an empty table. In the State pattern, though, it is easy to have a state that can go to only certain states and not others. In the three-way light example in Chapter 10, a light state in the second on state cannot go to either the first on state or the off state. It can go only to the third on state. (See Figure 10-5 in Chapter 10.) Such is not the case with most algorithms.

One of the many features of both the State and Strategy design patterns is that the Context participants avoid conditional statements. If you look at the examples in Chapter 10, you’ll notice that none have conditional statements. In the When to Use the State Pattern? section in Chapter 10, you will find pseudocode that illustrates the difficulty in moving from one cell to the next using conditional statements. (Never mind what it would take when new states are added to or changed in an existing set of states!)

Design patterns certainly do not advocate never using conditional or case statements, but in some patterns, such as the State and Strategy, they can make maintenance difficult. If a single strategy (encapsulated algorithm) is changed and it requires changing a whole set of conditional or case statements, there’s a greater chance that errors can be introduced. Further, in using either pattern, introducing conditional or case statements in the client participant is acceptable because all that the client does is make requests. Further, in the encapsulated algorithms (concrete strategies), carrying out a task may require a conditional or case statement. Likewise, in data output and error checking using mysqli, a conditional statement is often essential. Strategies eliminate conditional statements for selecting desired behavior. The different tasks are handled by the different concrete strategies, and because the client requests concrete strategies through the context, it must be aware of the available strategies. This does not mean that conditionals cannot be part of the client’s selection process. It means that conditionals are not part of the context.

In order to see the general pattern using a MySQL connection, this first example uses no table but instead sets up the pattern for later incorporation of the details in each strategy. Because the HTML form cannot pass selected parameters to a PHP class or file, this example uses several small PHP trigger scripts. The trigger scripts call different methods from a single client that in turn calls the requested concrete strategy through the context.

Figure 12-2 shows the file diagram for this implementation. The HTML file has separate forms for each strategy that is passed through a PHP trigger script to methods in the Client. The Client passes on the request through the Context to a concrete strategy. The connection helpers are an interface and class to connect to a MySQL database.

For those developers who have considerable experience dealing with MySQL databases, Figure 12-2 may appear to be an overengineered approach to a task. However, the purpose of design patterns is to make the objects available for change and reuse. Each of the concrete strategies is encapsulated so that any changes (maintaining the implemented interfaces) will not crash the system. Even from the perspective of this minimal strategy, it should be easy to see how the behaviors in the concrete strategies are open to a wide range of implementations.

The Client class makes requests through the Context, creating a concrete strategy. The request for the different strategies is accomplished with a set of methods. The following two lines are key in the request:

$context=new Context(new ConcreteStrategy());
$context->algorithm();

Each Client method provides the name of the concrete strategy to implement, and algorithm() is a Context method implemented in the concrete strategies. This process reveals how polymorphism works. Each request for the concrete method’s algorithm is through a Context instance, and so the requests for all of them look exactly alike: $context->algorithm(). However, the Client instantiates the Context with a concrete strategy as an argument. That argument allows the Context to use the requested concrete strategy by implementing the concrete strategy’s implementation of the algorithm() method. In this way, the Strategy pattern lets the algorithm vary independently from the clients that use it. Instead of having several different client classes, several different trigger scripts use the same client in the following example:

<?php
class Client
{
    public function insertData()
    {
        $context=new Context(new DataEntry());
        $context->algorithm();
    }

    public function findData()
    {
        $context=new Context(new SearchData());
        $context->algorithm();
    }

    public function showAll()
    {
        $context=new Context(new DisplayData());
        $context->algorithm();
    }

    public function changeData()
    {
        $context=new Context(new UpdateData());
        $context->algorithm();
    }

    public function killer()
    {
        $context=new Context(new DeleteRecord());
        $context->algorithm();
    }
}
?>

In order to fire the methods for the different concrete strategies (encapsulated algorithms), the HTML calls one of the following PHP trigger scripts:

<?php
//insertTrigger.php
function __autoload($class_name)
{
    include $class_name . '.php';
}
$trigger=new Client();
$trigger->insertData();
?>
-------------
<?php
//displayTrigger.php
function __autoload($class_name)
{
    include $class_name . '.php';
}
$trigger=new Client();
$trigger->showAll();
?>
-------------
<?php
//findTrigger.php
function __autoload($class_name)
{
    include $class_name . '.php';
}
$trigger=new Client();
$trigger->findData();
?>
-------------
<?php
//updateTrigger.php
function __autoload($class_name)
{
    include $class_name . '.php';
}
$trigger=new Client();
$trigger->changeData();
?>
-------------
<?php
//killTrigger.php
function __autoload($class_name)
{
    include $class_name . '.php';
}
$trigger=new Client();
$trigger->killer();
?>

The form in the HTML document calls each PHP trigger separately. The request from the trigger script is passed on to the client, which uses one method for each request. In Strategy design patterns, the client typically creates and passes a concrete object to the context. However, the request origins lie in the HTML document:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Test</title>
</head>
<body>
Insert<br />
<form name="insert" action="insertTrigger.php" method="post">
  <input type="text" name="data">
  <br />
  <input type="submit" value="Insert">
</form>
<br />
Find Data
<form name="find" action="findTrigger.php" method="post">
  <input type="text" name="data">
  <br />
  <input type="submit" value="Find">
</form>
<br />
Display All Data
<form name="display" action="displayTrigger.php" method="post">
  <input type="submit" value="Show all data">
</form>
<br />
Update Data
<form name="change" action="updateTrigger.php" method="post">
  <input type="text" name="data">
  <br />
  <input type="submit" value="Change data in record">
</form>
<br />
Delete Record
<form name="killer" action="killTrigger.php" method="post">
  <input type="text" name="data">
  <br />
  <input type="submit" value="Delete Record">
</form>
</body>
</html>

One of the tricky elements in this arrangement is protecting the $_POST data by using the mysqli->real_escape_string() method for extracting the data values sent from the HTML document. It would be possible to include an extra variable in all posts to indicate a concrete strategy request method that the client will use and then make the selection without using a gaggle of trigger scripts. The MySQL connection could be made in the client, making it possible to extract the data, close the connection, and then pass it on to the concrete strategy, where a second connection could be opened to process the request through the appropriate strategy. However, this example attempts to keep the focus on design patterns and not abandoning all security issues. One result is the separate trigger scripts for fulfilling a request.

In the State design, the Context class acts as a “track keeper”; it keeps track of the current state. In the Strategy design, the Context has a much different function. It serves to separate a request from a concrete strategy, thereby allowing the strategy and request to act independently of one another. It represents another form of loose binding between request and consequence. At the same time, it facilitates a request from the Client.

The Context is not an interface (of either the abstract class or interface variety), but it is aggregated with the Strategy interface. The Gang of Four specify the following characteristics:

In the following listing, you can see these features of a Context class:

<?php
class Context
{
    private $strategy;

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

    public function algorithm()
    {
        $this->strategy->algorithm();
    }
}
?>

First, the constructor function expects an implementation of IStrategy as a parameter. Second, it maintains a reference to a Strategy object through an encapsulated (private visibility) property, $strategy. The $strategy property receives its instance from the constructor parameter that will be an instance of a concrete strategy. Third, the algorithm() method implements IStrategy method, also named algorithm() as implemented by the concrete strategy selected through the Client. Because the Context and IStrategy make up an aggregation, the Context has certain features of an abstract class or interface. In fact, a Context may be best understood in the aggregation. In looking at the Strategy interface, IStrategy, you can see the single method to be implemented is algorithm():

<?php
interface IStrategy
{
    public function algorithm();
}
?>

Each concrete strategy can implement the method in any fashion required.

The encapsulated family of algorithms that makes up the concrete strategies provides a mockup of possible strategies. The point in this minimalist example is to see how the different participants in the Strategy design pattern work in concert. In this section, you will see a fully implemented example.

The five concrete strategies include the following classes:

Each of these concrete strategies represents typical algorithms used with PHP and MySQL.

In the minimalist example in the previous section, you were able to see all of the basic elements of a Strategy design pattern in PHP using a MySQL database. To make a more robust example, this next example adds functionality to the different strategies. It also adds a helper class to deal with a secure movement of data from the HTML client to the MySQL database. This means that the client is able to make secure requests using data passed through the mysqli->real_escape_string($_POST['data']) function. The Client class could handle the security itself, but that would give it an added responsibility beyond making the requests.

Using the mysqli->real_escape_string($_POST['data']) function to pass data securely between the HTML form and the PHP class requires a MySQL connection, but once the connection has been opened and the data securely passed, it can be closed again to free up resources used by the connection.

Anticipating the different concrete strategies, the helper class has unique methods for securing data for each of the concrete strategies. A single method passes an array back to the Client containing the required data for the request. Figure 12-3 diagrams the relationship of the helper class to the Strategy.

The rest of the Strategy pattern is not shown in Figure 12-3 after the Context class, but it follows the standard class diagram shown in Figure 12-1. Also, the same MySQL helper classes that are used for database requests are used with the SecureData class to create the MySQL connection.

The SecureData class has methods for each of the concrete strategies that rely on data from the HTML forms. The DisplayAll concrete strategy requests that all data be displayed, and so it needs no special data passed from the HTML form:

<?php
//Helper class
//SecureData.php
class SecureData
{
    private $changeField;
    private $company;
    private $devdes;
    private $device;
    private $disappear;
    private $field;
    private $hookup;
    private $lang;
    private $newData;
    private $oldData;
    private $plat;
    private $style;
    private $term;
    //$dataPack will be an array
    private $dataPack;

    public function enterData()
    {
        $this->hookup=UniversalConnect::doConnect();
        $this->company=$this->hookup->real_escape_string($_POST['company']);
        $this->devdes=$this->hookup->real_escape_string($_POST['devdes']);
        $this->lang= $this->hookup->real_escape_string($_POST['lang']);
        $this->plat= $this->hookup->real_escape_string($_POST['plat']);
        $this->style=$this->hookup->real_escape_string($_POST['style']);
        $this->device=$this->hookup->real_escape_string($_POST['device']);
        $this->dataPack=array(
            $this->company,
            $this->devdes,
            $this->lang,
            $this->plat,
            $this->style,
            $this->device
        );

        $this->hookup->close();
    }

    public function conductSearch()
    {
        $this->hookup=UniversalConnect::doConnect();
        $this->field=$this->hookup->real_escape_string($_POST['field']);
        $this->term=$this->hookup->real_escape_string($_POST['term']);
        $this->dataPack=array(
            $this->field,
            $this->term
            );
        $this->hookup->close();
    }

    public function makeChange()
    {
        $this->hookup=UniversalConnect::doConnect();
        $this->changeField=$this->hookup->real_escape_string($_POST['update']);
        $this->oldData=$this->hookup->real_escape_string($_POST['old']);
        $this->newData=$this->hookup->real_escape_string($_POST['new']);
        $this->dataPack=array(
            $this->changeField,
            $this->oldData,
            $this->newData
            );
        $this->hookup->close();
    }

    public function removeRecord()
    {
        $this->hookup=UniversalConnect::doConnect();
        $this->disappear=$this->hookup->real_escape_string($_POST['delete']);
        $this->dataPack=array($this->disappear);
        $this->hookup->close();
    }

    //Returns secure data as array to requesting Client
    public function setEntry()
    {
        return $this->dataPack;
    }
}
?>

All of the methods except for setEntry() generate an array named dataPack. The setEntry() method returns the current contents of dataPack. Depending on the request, the SecureData class generates values placed into the array, which is passed back to the Client and becomes part of a request to a concrete strategy through the algorithm() method.

The following script is used to create a table for the survey. Larger or smaller tables can be used with the Strategy design by altering the size of the array used in the concrete strategies:

<?php
include_once('UniversalConnect.php');
class CreateTable
{
    private $tableMaster;
    private $hookup;

    public function __construct()
    {
        $this->tableMaster="survey";
        $this->hookup=UniversalConnect::doConnect();

        $drop = "DROP TABLE IF EXISTS $this->tableMaster";

        if($this->hookup->query($drop) === true)
        {
            printf("Old table %s has been dropped.<br/>",$this->tableMaster);
        }

        $sql = "CREATE TABLE $this->tableMaster (
            id SERIAL,
            company     NVARCHAR(40),
            devdes      NVARCHAR(10),
            lang        NVARCHAR(15),
            plat        NVARCHAR(15),
            style       NVARCHAR(20),
            device      NVARCHAR(10),
            PRIMARY KEY (id))";

        if($this->hookup->query($sql) === true)
        {
            printf("Table $this->tableMaster has been created successfully.
                    <br/>");
        }
        $this->hookup->close();
    }
}
$worker=new CreateTable();
?>

This particular table-creation class is used during the development and debugging cycle. Once you have your table the way you want it and want it installed on different systems, you can remove the following section:

$drop = "DROP TABLE IF EXISTS $this->tableMaster";

if($this->hookup->query($drop) === true)
{
    printf("Old table %s has been dropped.<br/>",$this->tableMaster);
}

and change the following code:

$sql = "CREATE TABLE $this->tableMaster (

to the following:

$sql = "CREATE TABLE IF NOT EXISTS $this->tableMaster (

In this way, the class will not remove any existing tables that may have data already stored in them.

The same UniversalConnect class is employed as with all of the other MySQL connections in this chapter.

Given the job of the SecureData helper class and the revised IStrategy interface to include a parameter for the algorithm() method, Client can more easily make requests based on methods for the various requests from the HTML forms. Before going on, take a look at the requests originating in the HTML forms. Two forms are used: one for user input of survey data and one for viewing the data stored in a MySQL table. All are very simple and represent generic HTML forms. Both forms share a single CSS file:

@charset "UTF-8";
/*survey.css */
/* CSS Document */
/*B2B2B2,B2A1A1,666666,8FB299*/
body
{
    background-color:#B2B2B2;
    color:#666666;
    font-family:Verdana, Geneva, sans-serif
}

h2
{
    font-family:"Arial Black", Gadget, sans-serif;
    color:#666666
}

h3
{
    font-family:"Trebuchet MS", Arial, Helvetica, sans-serif;
    background-color:#8FB299;
    color:#666666
}

th
{
    text-align:left;
    background-color:#8FB299;
    color:#666666
}

The CSS is set for minimum differentiation.

First, the survey is a simple text entry plus several selections from radio forms:

<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="survey.css">
<meta charset="UTF-8">
<title>Programmer Profile Survey</title>
</head>
<body>
<h2>Programmer Survey</h2>
<form name="survey" action="insertTrigger.php" method="post">
  <input type="text" name="company">
  &nbsp;Company Name<br />
  <h3>&nbsp;Primary Role</h3>
  <input type="radio" name="devdes" value="developer">
  &nbsp;Developer<br />
  <input type="radio" name="devdes" value="designer">
  &nbsp;Designer<br />
  <h3>&nbsp;Primary Programming Language</h3>
  <input type="radio" name="lang" value="PHP">
  &nbsp;PHP<br />
  <input type="radio" name="lang" value="C#/ASP.NET">
  &nbsp;C# ASP.NET<br />
  <input type="radio" name="lang" value="PERL">
  &nbsp;PERL<br />
  <input type="radio" name="lang" value="JavaScript">
  &nbsp;JavaScript<br />
  <input type="radio" name="lang" value="ActionScript 3.0">
  &nbsp;ActionScript 3.0<br />
  <h3>&nbsp;Primary Development/Design Platform</h3>
  <input type="radio" name="plat" value="WinPC">
  &nbsp;Windows PC<br />
  <input type="radio" name="plat" value="Mac">
  &nbsp;Apple Macintosh<br />
  <input type="radio" name="plat" value="Linux">
  &nbsp;Linux<br />
  <h3>&nbsp;Primary Programming Style</h3>
  <input type="radio" name="style" value="sequential">
  &nbsp;Sequential<br />
  <input type="radio" name="style" value="procedural">
  &nbsp;Procedural<br />
  <input type="radio" name="style" value="OOP">
  &nbsp;Object Oriented Programming<br />
  <input type="radio" name="style" value="design patterns">
  &nbsp;Design Patterns
  <p />
  <h3>&nbsp;Primary Platform Development/Design</h3>
  <input type="radio" name="device" value="Desktop">
  &nbsp;Desktop<br />
  <input type="radio" name="device" value="Tablet">
  &nbsp;Tablet<br />
  <input type="radio" name="device" value="Smartphone">
  &nbsp;Smartphone
  <p />
  <input type="submit" value="Create Profile" name="sender">
</form>
</body>
</html>

Figure 12-4 shows the survey opened in a tablet device.

A second HTML document provides an administrative tool for examining the table. Again, it is quite simple and used primarily for following the data from its origins in an HTML form through a Strategy design pattern:

<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="survey.css">
<meta charset="UTF-8">
<title>Administrative Module</title>
</head>

<body>
<h2>Administrative Module</h2>
<h3>&nbsp;Display all data</h3>
<form name="allData" action="displayTrigger.php" method="post">
  <input type="submit" value="Display Data" name="display">
</form>
<form name="search" action="findTrigger.php" method="post">
  <h3>&nbsp;Search Field</h3>
  <input type="radio" name="field" value="id">
  &nbsp;ID<br />
  <input type="radio" name="field" value="company">
  &nbsp;Company<br />
  <input type="radio" name="field" value="devdes">
  &nbsp;Designer/Developer<br />
  <input type="radio" name="field" value="lang">
  &nbsp;Computer Language<br />
  <input type="radio" name="field" value="plat">
  &nbsp;Development Platform<br />
  <input type="radio" name="field" value="style">
  &nbsp;Programming Style<br />
  <input type="radio" name="field" value="device">
  &nbsp;Target Device
  <p />
  <input type="text" name="term">
  &nbsp;Term to find
  <p />
  <input type="submit" value="Search" name="searcher">
</form>
<form name="search" action="changeTrigger.php" method="post">
  <h3>&nbsp;Change Field</h3>
  <input type="radio" name="update" value="id">
  &nbsp;ID <br />
  <input type="radio" name="update" value="company">
  &nbsp;Company<br />
  <input type="radio" name="update" value="devdes">
  &nbsp;Designer/Developer<br />
  <input type="radio" name="update" value="lang">
  &nbsp;Computer Language<br />
  <input type="radio" name="update" value="plat">
  &nbsp;Development Platform<br />
  <input type="radio" name="update" value="style">
  &nbsp;Programming Style<br />
  <input type="radio" name="update" value="device">
  &nbsp;Target Device
  <p />
  <input type="text" name="old">
  &nbsp;Old Value
  <p />
  <input type="text" name="new">
  &nbsp;New Value
  <p />
  <input type="submit" value="Change Value" name="changer">
</form>
<h3>&nbsp;Delete Record</h3>
<form name="killer" action="killTrigger.php" method="post">
  <input type="text" name="delete" size=3>
  &nbsp;Number of Record to Delete
  <p />
  <input type="submit" value="Permanently Delete Record" name="doa">
</form>
</body>
</html>

Figure 12-5 shows the UI displayed on a tablet device.

Both UIs use a mobile layout of a single column that can be adjusted for viewing on mobile phones with Internet capabilities.

Each button in the two HTML documents represents a separate form. Each form calls a trigger file that in turn instantiates the Client class and the appropriate method required to carry out the requested task.

The Client has no constructor function, but instead it has several methods available for different requests. The methods are similar to the minimalist example, but they do more with the help of a SecureData helper class discussed previously, in A Data Security Helper Class.

First, review what the SecureData class does, and then take a look at the Client:

<?php
//Client.php
class Client
{
    public function insertData()
    {
        $secure=new SecureData();
        $context=new Context(new DataEntry());
        $secure->enterData();
        $context->algorithm($secure->setEntry());
    }

    public function findData()
    {
        $secure=new SecureData();
        $context=new Context(new SearchData());
        $secure->conductSearch();
        $context->algorithm($secure->setEntry());
    }

    public function showAll()
    {
        $dummy=array(0);
        $context=new Context(new DisplayAll());
        $context->algorithm($dummy);
    }

    public function changeData()
    {
        $secure=new SecureData();
        $context=new Context(new UpdateData());
        $secure->makeChange();
        $context->algorithm($secure->setEntry());
    }

    public function killer()
    {
        $secure=new SecureData();
        $context=new Context(new DeleteRecord());
        $secure->removeRecord();
        $context->algorithm($secure->setEntry());
    }
}
?>

With the exception of the showAll() method, all of the methods in the Client first instantiate the SecureData class. Then the methods create a context object, using the concrete method as a parameter. Next, the SecureData object calls the appropriate method related to the concrete strategy to create the required array. Finally, the Client method calls the Context->algorithm() using the array, $secure->setEntry() returned from the SecureData class as an argument. The array contents depend on user input sent from the HTML form and the type of strategy requested.

The Gang of Four point out that all concrete strategy classes share the same interface whether they are used or not. Therefore all concrete strategy classes must implement the method in the Strategy interface (the algorithm() method in IStrategy). However, not all concrete strategies may need the algorithm and certainly not in the same way.

To some extent, you can see this in the showAll() method in the Client class. Instead of using an array returned from the SecureData class, it creates a dummy array containing it and uses it as a parameter in the Context->algorithm(). This is one way to meet the requirements of the IStrategy interface to include an array as a parameter.

The whole purpose of passing data through an array to the concrete strategies is to allow the different strategies to respond to different requests. It gives flexibility to the design because of the wide range of data that can be passed with an array. As you can see in the following concrete strategy classes, each implements the IStrategy algorithm() method using the data passed through the methods array parameter.

All of the concrete classes use the same UniversalConnect class as used in the minimalist strategy example. The table name is stored as a constant (TABLENOW) in the IStrategy interface.

The search algorithm selects a specified value from a specified field. The field name and search value are passed through the array as an argument in the algorithm() method. A match results in the record being displayed, while nothing is displayed when there’s no match:

<?php
//SearchData.php
class SearchData implements IStrategy
{
    private $tableMaster;
    private $dataPack;
    private $hookup;
    private $sql;

    public function algorithm(Array $dataPack)
    {
        $this->tableMaster=IStrategy::TABLENOW;
        $this->hookup=UniversalConnect::doConnect();
        $this->dataPack=$dataPack;
        $field=$this->dataPack[0];
        $term=$this->dataPack[1];
        $this->sql = "SELECT * FROM $this->tableMaster WHERE $field='$term'";
        //Conditional statement in MySQL query for data output
        if ($result = $this->hookup->query($this->sql))
        {
            echo "<link rel='stylesheet' href='survey.css'>";
            echo "<table>";
            while($row=mysqli_fetch_row($result))
            {
                echo "<br />";
                echo "<tr>";
                foreach($row as $cell)
                {
                    echo "<td>$cell</td>";
                }
                echo "</tr>";
        }
        echo "</table>";
        $result->close();
    }
    $this->hookup->close();

    }
}
?>

A more sophisticated algorithm and display design can be easily substituted. If more data is required, it is a simple matter to change the data generated in the HTML document and placed into an array in the SecureData class. This can be done without affecting any other components of the program, and this is in no small part the sine qua non of design patterns overall. Figure 12-7 shows a search for “designer” in the Designer/Developer field.

The Strategy pattern is so flexible that not only can changing the algorithm change one implementation, but also the pattern itself has more than one implementation. On the one hand, this chapter showed how the minimalist version of the Strategy design pattern could call up different algorithms that worked independent of data outside of the concrete strategy. On the other hand, the second example used parameters that passed secure data to the concrete strategies.

The Gang of Four point out that one approach is to have the Context pass data in parameters to Strategy operations. That is exactly what the second example did. This approach takes the data to the strategy, whereas keeping the Context and Strategy decoupled may also pass data to the Strategy that it does not need. The approach to this dilemma was to use an array to add flexibility in what was passed to the Strategy. This included an empty array.

The particular type of Strategy implementation depends on the needs of the particular algorithm and what it requires. Some implementations of the Strategy involve storing a reference to its context, which eliminates the need to pass anything. However, in so doing, it more tightly couples the Context and Strategy.

A further issue to consider is the number of objects the Strategy pattern generates in the form of concrete strategies. As you’ve seen in the examples, quite a few objects (classes) are built to handle the different requests made in a simple MySQL survey run by PHP. More could be built. However, that may not be as big a problem in view of the advantages in reuse and change of the pattern. Design patterns are built for speed in managing an application, but not executing code. A developer with a well-organized Strategy pattern can easily optimize and reoptimize the encapsulated algorithms without it falling in around his head. So the speed is in the reuse and change time, and the cost of additional objects is a small expense.