Take the 2-minute tour ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

I've been reading The Pragmatic Programmer for a few days and I've come across a reference to the strategy pattern. Looked it up in Design Patterns and figured I could refactor a piece of code I'm currently working on to comply with the strategy pattern.

I need to process text using many string algorithms much like Lucene analyze and tokenize text. This is for an importation routine. Strategy:

public class ChainOfProcessor: IStringProcessor
{
    public List<IStringProcessor> Processors;

    public ChainOfProcessor()
    {
        Processors = new List<IStringProcessor>();
    }

    public ChainOfProcessor Add<TProcessor>()
        where TProcessor: IStringProcessor, new()
    {
        return Add(new TProcessor());
    }

    public ChainOfProcessor Add(IStringProcessor processor)
    {
        Processors.Add(processor);
        return this;
    }

    public string Process(string input)
    {
        return Processors.Aggregate(input, (current, processor) => processor.Process(current));
    }
}

public interface IStringProcessor
{
    string Process(string input);
}

public class HtmlStripper: IStringProcessor
{
    public virtual string Process(string input)
    {
        var htmlDoc = new HtmlDocument();
        htmlDoc.LoadHtml(input);
        return htmlDoc.DocumentNode.InnerText;
    }
}

public class HtmlDecoder: IStringProcessor
{
    public string Process(string input)
    {
        return HttpUtility.HtmlDecode(input);
    }
}

In Design Patterns, the authors use a Composition class and Compositor classes as examples. The client is allowed to chose a single Compositor through Composition to do whatever the Compositor is supposed to do. There is a subtle difference in how the client uses the Composition in my example. Instead of allowing a single IStringProcessor to be used through some Composition class, I allow many, to be executed one after the other through the concrete class ChainOfProcessor. Usage:

var text = new ChainOfProcessor()
    .Add<HtmlStripper>()
    .Add<HtmlDecoder>()
    .Process(html);
share|improve this question

3 Answers 3

up vote 7 down vote accepted

It seems like a you should implement Chain of responsibility as you are passing the same string to different kind of processor with a particular sequence

http://www.dofactory.com/Patterns/PatternChain.aspx#_self1

This is a gud pattern in your scenario.

One more thing your StringProcessorChain might not be needed in this case....

Let me know if you need a more highlight on same

share|improve this answer
    
It bothers me to write chaining code in every single processor. Also, usability is reduced on the client for large chains of processors; In the end it requires more code on the client and the framework. –  maxbeaudoin Nov 8 '12 at 19:34
1  
You could make an abstract StringProcessorBase class that has the chaining code, and make your processors extend that... –  cHao Nov 8 '12 at 22:38

Minor stylistic things (not exposing a public List), etc. But otherwise, you're looking good:

public interface IStringProcessor
{
    string Process(string input);
}

public sealed class ChainOfProcessor : IStringProcessor
{
    private readonly IList<IStringProcessor> processors = new List<IStringProcessor>();

    public IList<IStringProcessor> Processors
    {
        get
        {
            return this.processors;
        }
    }

    public ChainOfProcessor Add<TProcessor>() where TProcessor : IStringProcessor, new()
    {
        return Add(new TProcessor());
    }

    public ChainOfProcessor Add(IStringProcessor processor)
    {
        this.processors.Add(processor);
        return this;
    }

    public string Process(string input)
    {
        return this.processors.Aggregate(input, (current, processor) => processor.Process(current));
    }
}

public class HtmlStripper : IStringProcessor
{
    public virtual string Process(string input)
    {
        var htmlDoc = new HtmlDocument();

        htmlDoc.LoadHtml(input);
        return htmlDoc.DocumentNode.InnerText;
    }
}

public sealed class HtmlDecoder : IStringProcessor
{
    public string Process(string input)
    {
        return HttpUtility.HtmlDecode(input);
    }
}
share|improve this answer

I would call this an implementation of the Composite pattern.

The strategy pattern is about choosing one from a selection of techniques to accomplish a goal. A common example is different formatting (xml or json) or different storage (db or file system). The encapsulation is around which choice is made.

In the composite pattern, an implementation of an interface delegates to N other implementation according to some algorithm (like "call all of them in order"). The encapsulation is cardinality of child objects being called. This is a very good example of exactly that.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.