Introducing the Strategy Pattern

The strategy design pattern can be very useful in the context of form validation. This article, the first of two parts, will introduce you to the strategy pattern and give you some idea of how you can use it in your own PHP applications.

Whether you’re a PHP developer who has been using this useful server-side scripting language for a while, or a seasoned programmer who has spent many years developing PHP-driven web applications, it’s highly probable that you have already used (deliberately or not) a design pattern.

While this isn’t a fact that is going to change the way you create your PHP programs permanently, the truth is that there are certain design patterns that are much more common to implement during the development of specific web applications than others.

Naturally, this concept may sound strange at first, particularly if you’re just starting to dig deeper into the huge and fascinating terrain of PHP-based programming, but consider this: how many times have you used the "new" PHP keyword to create an instance of a particular class? Or, more to the point, how many times have you utilized the "&" operator to avoid working with multiple instances of that class?

Probably the answer to the above questions is tens or hundreds of times, right? In these cases you used a basic implementation of the Factory and Singleton patterns respectively, maybe without being aware of it.

As you can see, there are certain design patterns that are more usually applied than others. That’s exactly the case with the subject of this article, the strategy pattern. To put things more clearly, I’m sure that you always validate adequately all the forms included in your web sites. First off, you create a few validation functions (or classes), then use these functions to check the validity of the data supplied by users, and finally determine the course of action to be taken accordingly.

In the example that I described above, you first selected a context where the corresponding form validation was going to take place, and then applied a data checking strategy to establish programmatically how different types of user inputs will be verified.

Certainly, this is a concrete implementation of the strategy design pattern, in a situation that should be familiar to you! In other words, when this pattern is applied, there will be a predefined context (in object-based programming this is represented by a context class) that will be capable of selecting what type of action must be taken, in accordance with the requirement of a specific strategy (again, in OOP this is achieved by coding different extensions of a class interface).

Now that you know at least in theory how the strategy pattern works, in this two-part series I’m going to demonstrate the practical side of this topic. I will provide you with some illustrative examples that hopefully will help you understand how the pattern can be included in your own PHP applications.

Ready to face this challenge? All right, let’s go!

{mospagebreak title=A basic example of the design strategy pattern: building a file data handling class}

A good point to begin demonstrating how the strategy pattern works is with developing an adequate context, where you can easily see the functionality provided by the pattern in question.

Therefore, I’m going to build a file data handling class which will be capable of performing some handy tasks, like reading and writing strings of data to a specified file location.

Later on, I’m going to create a contextual class, which will determine programmatically what type of format should be applied to all the data returned by the aforementioned file data handler. In this case, two output formats will be available: HTML and XML. As usual, this condition can be easily modified to expand the capacity of the contextual class.

And finally, after defining all the classes that I discussed earlier, I’m going to establish a strategy between them, so you can see how the aptly-named strategy pattern works. Pretty simple, isn’t it?

Now that I have explained how I’m going to apply the strategy pattern here, pay attention to the signature of the following class. As I said before, it is tasked with performing some basic file handling operations. Its structure is as follows:

// define ‘FileReader’ class
class FileDataHandler{
   private $dataFile;
   private $data;
   public function __construct($data=’default data’,
$dataFile=’default_data_file.txt’){
     if(!$data||!is_string($data)){
       throw new Exception(‘Invalid string of data!’);
     }
     if(!file_exists($dataFile)){
       throw new Exception(‘Invalid data file!’);
     }
     $this->data=$data;
     $this->dataFile=$dataFile;                     
   }
   // write data to file
   public function writeData(){
     if(!$fp=fopen($this->dataFile,’w')){
       throw new Exception(‘Error opening data file!’);
     }
     if(!fwrite($fp,$this->data)){
       throw new Exception(‘Error writing data to file!’);
     }
     fclose($fp);
   }
   // read data from file
   public function readData(){
     if(!$contents=file_get_contents($this->dataFile)){
       throw new Exception(‘Error reading data from file!’);
     }
     return $contents;
   }
}

As you can see, the signature of the above file data handling class is indeed simple to grasp. As I expressed before, this class exposes some basic methods, which come in handy for reading data from a specified file, as well as writing new contents to it.

Obviously, these operations are carried out by the "readData()" and "writeData()" methods respectively, so until now, the prior "FileDataHandler" class shouldn’t present any problems to you.

Also, a possible use for the previous class can be seen by the example below:

try{
   // example using the ‘FileDataHandler’ class
   $fdHandler=new FileDataHandler();
   $fdHandler->writeData();
   echo $fdHandler->readData();
}
catch(Exception $e){
   echo $e->getMessage();
   exit();
}

Not surprisingly, the output generated by the above example is the following:

default data

Pretty basic, isn’t it? Nonetheless, this is where things are getting really exciting. In the section that you’re about to read, I’m going to define a contextual class. It will be responsible for determining what format should be applied to the data read by the previous file data handing class (HTML or XML), in this way implementing a formatting strategy, or what’s commonly called "the strategy pattern."

To see how this contextual class will be created, keep reading.

{mospagebreak title=Establishing a formatting strategy: defining a contextual class}

Since I’m using object-based programming with PHP 5, the creation of a context where the strategy pattern can be applied will be performed by a single contextual class. However, if you’re working with a procedural approach, creating the aforementioned context should be as simple as defining some functions tasked with implementing a predefined strategy.

Having said that, let me show you the signature for this new contextual class, which I called "StrategySelector." It looks like this:

// define ‘StrategySelector’ class
class StrategySelector{
    private $strategy=NULL;
    public function __construct($strategy){
      if($strategy!=’html’&&$strategy!=’xml’){
        throw new Exception(‘Invalid value for strategy!’);
      }
      if($strategy==’html’){
        $this->strategy=new StrategyHTML();
      }
      else{
        $this->strategy=new StrategyXML();
      }
    }
    public function displayFileContents(FileDataHandler
$dataFileHandler){
      return $this->strategy->displayFileContents
($dataFileHandler);
    }
}

Even when the definition of the above contextual class is rather short, it indeed tells a lot about how the strategy pattern works. As you can see, the previous "StrategySelector" class takes up a $strategy" parameter via the corresponding constructor, and according to the value of this argument, that is "html" or "xml," it creates the correct "strategy" object. This object will be used for formatting contents fetched by the file data handler that was shown in the previous section.

So, summarizing, on one hand I created a class that defines the context where different formatting strategies will be applied, while on the other hand, there’s a couple of objects that implement these strategies. Are you starting to grasp the logic that stands behind the strategy pattern? I bet you are!

But now, let me go straight to the point and show you the signatures that correspond to the pair of strategy classes that were shown previously, that is "StrategyHTML" and "StrategyXML." The respective definitions for these new classes are as follows:

// define ‘StrategyHTML’ class
class StrategyHTML{
    // return contents of data file as HTML
    public function displayFileContents(FileDataHandler
$dataFileHandler){
      return ‘<div><h2>Contents of data file, formatted as HTML
are as follows</h2><p>’.$dataFileHandler->readData().’</p></div>’;
    }
}
// define ‘StrategyXML’ class
class StrategyXML{
    // return contents of data file as XML
    public function displayFileContents(FileDataHandler
$dataFileHandler){
      return ‘<?xml version="1.0" encoding="iso-8859-1"?>
<data><filedata>’.$dataFileHandler->readData().
‘</filedata></data>’;
    }
}

As shown above, the two previous strategy classes expose the same "displayFileContents()" method, although obviously they offer different implementations. In the first case, contents fetched via the file data handler class will be outputted as HTML, while in the second case, the same contents will be formatted as XML.

At this point, I’m pretty certain that you’ve already learned how the strategy pattern works in this situation, where the pattern is applied to format data fetched from a remote file.

However, there is still a missing piece in the previous scenario, since you haven’t yet seen how the strategy selector and the respective strategy classes can be put to work in conjunction. Therefore, keeping in mind this situation, in the section to come I’m going to show you an illustrative example where all prior classes are going to be used together.

Want to see how this educational example will be developed? Go ahead and read the next few lines. I’ll be there, waiting for you.

{mospagebreak title=Understanding how the strategy pattern works: creating an example}

As I stated in the section that you just read, below I set up a couple of illustrative examples. These show in a friendly fashion how all the classes that you learned before can be put to work together, in this way demonstrating the functionality provided by the strategy design pattern.

That being said, please have a look at the following pair of code listings:

(example formatting data file as HTML)

try{
   // instantiate ‘FileDataHandler’ class
   $fdHandler=new FileDataHandler(‘This string will be formatted
depending on the context!’);
   // write data to file
   $fdHandler->writeData();
   // instantiate ‘StrategyHTML’ class
   $strategyHTML=new StrategySelector(‘html’);
   // display file contents formatted as HTML
   echo $strategyHTML->displayFileContents($fdHandler);
   // instantiate ‘StrategyXML’ class
   $strategyXML=new StrategySelector(‘xml’);
   // display file contents formatted as XML
   header(‘Content-type: text/xml; charset=iso-8859-1′);
   echo $strategyXML->displayFileContents($fdHandler);
}
catch(Exception $e){
   echo $e->getMessage();
   exit();
}

(example formatting data file as XML)

try{
   // instantiate ‘FileDataHandler’ class
   $fdHandler=new FileDataHandler(‘This string will be formatted
depending on the context!’);
   // write data to file
   $fdHandler->writeData();
   // instantiate ‘StrategyXML’ class
   $strategyXML=new StrategySelector(‘xml’);
   // display file contents formatted as XML
   header(‘Content-type: text/xml; charset=iso-8859-1′);
   echo $strategyXML->displayFileContents($fdHandler);
}
catch(Exception $e){
   echo $e->getMessage();
   exit();
}

As you can see, the first example uses the "StrategyHTML" class to format file data as HTML, while the second example returns this data to calling code as XML. For reasons of clarity, I broke the two examples into different pieces of code, but if you don’t need to use the "header()" PHP function, you can merge them into one single code block.

Final thoughts

In this first part of the series, I introduced the basic concepts concerning the implementation of the strategy pattern in PHP 5. As you saw, this pattern can be used in multiple contexts, and also utilize a wide range of predefined strategies.

In the second (and last) installment of the series, I’m going to show you how to use this neat pattern for a more useful purpose: validating user-supplied data. You won’t want to miss it!

[gp-comments width="770" linklove="off" ]
antalya escort bayan antalya escort bayan