Thursday, June 2, 2011

Design Patterns - Strategy

Strategy Pattern Definition: the Strategy Pattern defines a family of algorithms,encapsulates each one,and makes them interchangeable. Strategy lets the algorithm vary independently from clients that use it.

I know a lot of websites are quite simple and some web developers only know CURD and once the domain logic becomes complex, they start to struggle and start to create crap. But, anyway, complex conditional logic is one thing that makes program hard to read & understand. To improve readability, We can replace conditional logic with strategy pattern + factory pattern.

For example, we have logic below:
//some how we get a format value dynamically
$format  = $objOne->getFormat();
$context = $objTwo->getContext();

if ($format === 'xml') {
    //start to format $context into xml format
} elseif ($format === 'txt') {
    //format text
} elseif ($format === $somethingElse && $someotherConditionCheck) {
    //another format implementation
}

Let's see how to use Strategy and Factory Pattern to improve the code.

From the definition, we know that we should define an interface for a set of algorithms, for example:

interface FormatStrategy
{
    public function format($content);
}

Now, we can implement our algorithms. Each one is a separate class that implements FormatStrategy Interface:
class XmlFormat implements FormatStrategy
{
    public function format($content)
    {
        //do some xml format
        return $content . ' in xml';
    }
}

class TxtFormat implements FormatStrategy
{
    public function format($content)
    {
        //do some txt format
        return $content . ' in text';
    }
}
We defined two for algorithms and they both implement the same interface. Next, we must define some kind of strategy selector(Factory):

class FormatStrategySelector
{
    public static function getStrategy($strategy) 
    {
        switch($strategy) 
        {
            case 'xml':
                return new HtmlFormat();
                break;
            default:
                return new TxtFormat();
                break;
        } 
    }
}

To use strategy:

$format  = $objOne->getFormat();
$context = $objTwo->getContext();

$formattedContent = FormatStrategySelector::getStrategy($format)->format($context);

No comments: