Using Multiple Strategy Classes with the Strategy Design Pattern

Being one of the most popular contenders in the exciting, but very often complex, terrain of software design, the Strategy design pattern is a well-trusted paradigm. It allows you to build more flexible and efficient applications by appealing to the functionality of two of the big pillars of solid object-oriented programming: favoring Composition over Inheritance, and encapsulating the concepts that vary. This is the conclusion to a six-part series that shows you how to use the Strategy design pattern to validate incoming data.

As with other design patterns, the implementation of the Strategy pattern isn’t subject to a specific programming language or context, and in fact it may vary slightly from case to case. This doesn’t imply, though, that its use in real-world projects must be a painful and annoying experience. In reality, applying the model imposed by the pattern is most of the time a straightforward process, and it’s even easier to accomplish when using a language as PHP, whose learning curve is remarkably flat.

To prove how easy it is to apply the Strategy pattern in a real-world case, in previous parts of the series I developed a set of loosely-coupled classes. Each one was responsible for implementing a specific validation strategy, ranging from checking integer and float numbers to verifying email addresses and URLs. So far, I’ve demonstrated how to use the classes as standalone components; now it’s time to show how to put them to work together, so you can see how simple is to use these classes like LEGO blocks and assemble more complex strategies at run time.

With that premise in mind, in this last chapter of the series I’m going to build a sample application. It will use the aforementioned strategy classes to validate a set of inputted values in a very modular and flexible way. This instructive process will involve the use of Composition and Dependency Injection as well.

Now, it’s time to leave the theory behind us and show how to put the Strategy pattern to work for us in a truly useful fashion. Let’s get going!

{mospagebreak title=Review: the example classes developed so far}

As always, before I get my hands dirty and show how to build a flexible program that permits us to create different validation strategies at run time using all of the classes built in previous installments of the series, it’d be useful to recall how these classes looked.

So first, here’s the definition of a trivial form helper. Via its "addValidator()" method, it will take a predefined set of data checking objects, handy for setting up different validation strategies on the fly. Take a peek at it:

(FormHelper.php)

<?php

class FormHelper

{

    protected $_validators = array();

    protected $_errors = array();

   

    // add a validator

    public function addValidator(AbstractValidator $validator)

    {

        $this->_validators[] = $validator;

        return $this;

    }

   

    // get all the validators

    public function getValidators()

    {

        return !empty($this->_validators) ? $this->_validators : null;

    }

     

    // validate inputted data

    public function validate()

    {

        $validators = $this->getValidators();

        if (null !== $validators)

        {

            foreach ($validators as $validator)

            {

                if (!$validator->validate())

                {

                    $this->_errors[] = $validator->getFormattedError();

                }

            } 

        }

        return empty($this->_errors) ? true : false;

    }

   

    // get validation errors as an array

    public function getErrors()

    {

        return $this->_errors;

    }

   

    // get validation errors as a string

    public function getErrorString()

    {

        $errors = $this->getErrors();

        return !empty($errors) ? implode(”, $errors) : ”;

    }

   

    // clear state of the form helper

    public function clear()

    {

        $this->_validators = array();

        $this->_errors = array();

    }  

}

As you can see, the "FormHelper" class behaves like a container that houses different validation objects eventually injected via its "addValidator()" method. Once these objects are stored on the protected $_validators property, they’re used internally to check whether or not the supplied data is valid. Of course, you’ll understand the inner workings of this process much better when I show you a functional example, so pay attention to the following class, which defines the structure and behavior of generic validation objects:     

(AbstractValidator.php)

<?php

abstract class AbstractValidator

{

    protected $_value = ”;

    protected $_filter = ”;

    protected $_options = null;

    protected $_errorMessage = ”;

    protected $_errorPrefix = ‘<p>’;

    protected $_errorSufix = ‘</p>’;

   

    // constructor

    public function __construct($value, array $options = null)

    {

        $this->_value = $value;

        if (null !== $options)

        {

           $this->setOptions($options);

        }

    }

   

    // get supplied value

    public function getValue()

    {

        return $this->_value;

    }

   

    // set validation options

    public function setOptions(array $options)

    {

        if (empty($options))

        {

            throw new ValidatorException(‘Invalid options for the validator.’);

        }

        $this->_options = $options;

    }

   

    // get validation options

    public function getOptions()

    {

        return $this->_options;

    }

     

    // set the validation filter

    public function setFilter($filter)

    {

        if (!is_string($filter))

        {

            throw new ValidatorException(‘Invalid filter for the validator.’); 

        }

        $this->_filter = $filter;

    }

   

    // get the validation filter

    public function getFilter()

    {

        return $this->_filter;

    }

   

    // set the error message

    public function setErrorMessage($errorMessage)

    {

        if (!is_string($errorMessage))

        {

            throw new ValidatorException(‘Invalid error message for the validator.’);    

        }

        $this->_errorMessage = $errorMessage;

    }

   

    // get error message

    public function getErrorMessage()

    {

        return $this->_errorMessage;

    }

              

    // get formatted error string

    public function getFormattedError()

    {

        return $this->_errorPrefix . ‘The value ‘ . $this->getValue() . ‘ is incorrect. ‘ . $this->getErrorMessage() . $this->_errorSufix;

    }

   

    // validate the supplied value 

    public function validate()

    {

        return filter_var($this->getValue(), $this->getFilter(), $this->getOptions());  

    }

}

(ValidatorException.php)

<?php

class ValidatorException extends Exception{}

As you can see, this class validates a value passed to its constructor by using a specific PHP filter. This can be easily understood by analyzing the implementation of the class’ "validate()" method, which is merely a proxy for the built-in PHP "filter_var()" function.

Do you understand the logic behind this abstract validator? Great. Now, take a look at the following concrete classes, which are refined implementations of their abstract parent and can be used for checking integers, float numbers, email addresses and URLs by simply overriding a couple of inherited properties. Here they are:  

(IntegerValidator.php)

<?php

class IntegerValidator extends AbstractValidator

{

    protected $_filter = FILTER_VALIDATE_INT;

    protected $_errorMessage = ‘Please enter an integer value.’;

}

(FloatValidator.php)

<?php

class FloatValidator extends AbstractValidator

{

    protected $_filter = FILTER_VALIDATE_FLOAT; 

    protected $_errorMessage = ‘Please enter a float value.’;

}

(EmailValidator.php)

<?php

class EmailValidator extends AbstractValidator

{

    protected $_filter = FILTER_VALIDATE_EMAIL; 

    protected $_errorMessage = ‘Please enter a valid email address.’;

}

(UrlValidator.php)

<?php

class UrlValidator extends AbstractValidator

{

    protected $_filter = FILTER_VALIDATE_URL; 

    protected $_errorMessage = ‘Please enter a valid URL.’;

}

 

Done. At this point it’s clear to see that defining concrete subclasses that can be used for validating a specific type of data is a breeze. Of course, I could go on and on creating more validators, but that would be a waste of time, as the four we have now are enough to demonstrate how to set up distinct validation strategies at run time.

Now that we’ve reviewed all of the sample classes developed so far, the next step is to put these elements to work together. This way you can see how easy it is to validate incoming data using the set of strategy classes just analyzed.

This will be done in the coming section. So click on the link below and keep reading.

{mospagebreak title=The Strategy pattern in action}

Since the example that I’m about to show you will require using all of the classes shown previously, I’m going to define a basic autoloading class, which will save me from the hassle of including them manually. The autoloader will look like this:

<?php

class Autoloader

{

    private static $_instance;

   

    // get Singleton instance of the autoloader

    public static function getInstance()

    {

       if (!self::$_instance)

       {

           self::$_instance = new self;

       }

       return self::$_instance; 

    }

   

    // private constructor

    private function __construct()

    {

        spl_autoload_register(array($this, ‘autoload’)); 

    }

   

    // prevent cloning instance of the autoloader

    private function __clone(){}

   

    // autoload classes on demand

    public static function autoload($class)

    {

        $file = $class . ‘.php’;

        if (!file_exists($file))

        {

            require_once ‘FileNotFoundException.php’;

            throw new FileNotFoundException(‘The file containing the requested class was not found.’);

        }

        require $file;

        unset($file);

        if (!class_exists($class, false))

        {

            require_once ‘ClassNotFoundException.php’;

            throw new ClassNotFoundException(‘The requested class was not found.’);

        }

    }  

}

<?php

(ClassNotFoundException.php)

class ClassNotFoundException extends Exception{}

That was easy to follow, right? Basically, all that the previous "Autoloader" class do is include classes on demand (AKA lazing loading) using the SPL "spl_autoload_register()" function. With the autoloader already set, it’s time to create an example that shows how to validate a bunch of data according to a certain strategy. The script below does exactly that. Check it out: 

<?php

// include autoloader

require_once ‘Autoloader.php’;

$autoloader = Autoloader::getInstance();

// create an instance of the form helper

$formHelper = new FormHelper();

// add some validators to the form helper

$formHelper->addValidator(new IntegerValidator(10.5))

           ->addValidator(new FloatValidator(49.1))

           ->addValidator(new EmailValidator(‘bademailadress.com’))

           ->addValidator(new UrlValidator(‘http://www.devshed.com’));

// validate inputted data and display all error messages in one go

if (!$formHelper->validate())

{

    echo $formHelper->getErrorString();

      /*

    displays the following

    The value 10.5 is incorrect. Please enter an integer value.

    The value bademailadress.com is incorrect. Please enter a valid email address.

    */

}

else

{

    echo ‘The submitted data is correct!’;

}

As you can see, the above example implements at run time a validation strategy that requires checking first an integer value, then a float number and finally an email address and an URL. I don’t want to sound too verbose, but this simple script shows in all its splendor the power of the Strategy pattern: on one hand, the objects responsible for checking the supplied data are loosely-coupled, easily interchangeable components (remember the great OOP commandment "Encapsulate the concept that varies"?), while on the other hand the functionality offered by the objects in question is employed by the form helper via Composition, not Inheritance. In this case, we get the best of both worlds.

What’s more, the pattern implements a model so flexible that it makes it possible to "assemble" a whole new validation strategy by using fewer validator objects or even the same ones in a different sequence. To demonstrate how to accomplish this, in the last section of this tutorial I’m going to create another example, pretty similar to the previous one, which this time will implement a strategy that will permit us to validate only integers and email addresses.

So read the segment to come. It’s only one click away.

{mospagebreak title=Setting up a different validation strategy}

As I expressed in the past segment, it’s ridiculously easy to implement an entirely different validation strategy using the set of classes created previously. For demonstration purposes, say that you need to determine if a couple of values collected via an HTML form are an integer and a valid URL respectively. In a case like this, the entire checking process should be performed in the following way:   

<?php

// include autoloader

require_once ‘Autoloader.php’;

$autoloader = Autoloader::getInstance();

// create an instance of the form helper

$formHelper = new FormHelper();

// add a couple of validators to the form helper

$formHelper->addValidator(new IntegerValidator(5))

           ->addValidator(new EmailValidator(‘alejandro@domain.com’));

// validate inputted data and display all error messages in one go

if (!$formHelper->validate())

{

    echo $formHelper->getErrorString();

}

else

{

    echo ‘The submitted data is correct!’;

       /*

    displays the following

       The submitted data is correct!

    */

}

See how easy it is to switch over different validation strategies at run time? I bet you do! Since in this case the components responsible for checking inputted values are highly encapsulated objects, performing more complex (or stricter) validation is reduced to creating a few additional validator classes. It’s that simple, really.

And with this final example, I’m finishing this humble series on implementing the Strategy design pattern in PHP. Now that you surely have a clearer idea of the logic that stands behind this popular pattern, you may want to use it for adding extra flexibility to your own web applications.

Final thoughts

It’s hard to believe, but we’ve come to the end of this series. Hopefully the whole experience has been educational and even fun, as you learned how to implement the Strategy design pattern to tackle a real-world problem: validating incoming data in a truly flexible and modular way.

Taking into account the pattern’s flat learning curve and the numerous benefits that it introduces into the application of good object-oriented programming techniques, you may want to consider implementing it in your coming PHP project.

Meet you in the next PHP tutorial!

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