Question

I'm looking to abstract a helper method. The method needs to be able to take in an object, do things with it depending on the type of object, and return a value. Would it be better to do something like this:

interface ICanDo
{
 string DoSomething();
}

string DoThings(ICanDo mything)
{
 return mything.DoSomething();
}

Or is it better to do something like this:

interface IStrategy
{
 string DoSomething(object o);
}

string DoThings(object mything, IStrategy strategy)
{
 return strategy.DoSomething(mything);
}

Is the latter even using a strategy pattern, since the strategy isn't being built into the class?

Is there a better way to do this I'm not thinking of? Would it be better to build the strategy into the class, using a wrapper for any class that needs to have DoThings run on it?

Sorry--I'm new to this pattern and trying to figure out where and how to use it best.

This is what I ended up putting together. I'm unsure if this follows good development principles.

class IndexWrapper
{
    public interface IDocumentable
    {
        Document BuildDocument();
    }

    public interface IDocumentBuilder
    {
        Type SupportedType { get; }

        Document BuildDocument(object o);
    }

    public class StringDocumentBuilder : IDocumentBuilder
    {
        public Type SupportedType { get { return typeof(string); } }

        public Document BuildDocument(object o)
        {
            Document doc = new Document();
            doc.Add(new Field("string", o as string, Field.Store.YES, Field.Index.ANALYZED));
            return doc;
        }
    }

    public static class IndexableFactory
    {
        public static IDocumentable GetIndexableObject(object o)
        {
            return GetIndexableObject(o, DocumentBuilderFactory.GetBuilder(o));
        }

        public static IDocumentable GetIndexableObject(object o, IDocumentBuilder builder)
        {
            return new IndexableObject(o, builder);
        }
    }

    public static class DocumentBuilderFactory
    {
        private static List<IDocumentBuilder> _builders = new List<IDocumentBuilder>();

        public static IDocumentBuilder GetBuilder(object o)
        {
            if (_builders.Count == 0)
            {
                _builders = Assembly.GetExecutingAssembly()
                                   .GetTypes()
                                   .Where(type => typeof(IDocumentBuilder).IsAssignableFrom(type) && type.IsClass)
                                   .Select(type => Activator.CreateInstance(type))
                                   .Cast<IDocumentBuilder>()
                                   .ToList();
            }

            return _builders.Where(builder => builder.SupportedType.IsAssignableFrom(o.GetType())).FirstOrDefault();
        }
    }

    private class IndexableObject : IDocumentable
    {
        object _o;
        IDocumentBuilder _builder;

        public IndexableObject(object o) : this(o, DocumentBuilderFactory.GetBuilder(o)) { }
        public IndexableObject(object o, IDocumentBuilder builder)
        {
            _o = o;
            _builder = builder;
        }

        virtual public Document BuildDocument()
        {
            return _builder.BuildDocument(_o);
        }
    }
}
Was it helpful?

Solution

When in doubt, keep the KISS mantra in your mind - Keep It Short and Simple. Patterns can be very useful, but often they're only useful in specific cases and add unnecessary complexity otherwise.

In my experience, the strategy pattern is useful for when you have multiple different backends to choose from for a class. For example, say you have a logging class that your program uses to print debug information. Maybe in some cases, you want to log to a file. Maybe you'd like to log to a console. Perhaps you'd even like to log to a remote server with a proprietary protocol you company made!

So, your logging class may look like this:

interface IOutputWriter
{
    void WriteLn(string message);
}

class ConsoleWriter : IOutputWriter
{
    public ConsoleWriter()
    {

    }

    public void WriteLn(string message)
    {
        Console.WriteLine(message);
    }
}

class NetworkWriter : IOutputWriter
{
    public NetworkWriter()
    {

    }

    public void WriteLn(string message)
    {
        //Crazy propietary server protocol action
    }
}

class Logger
{
    IOutputWriter writer;
    public Logger(IOutputWriter writer)
    {
        this.writer = writer;
    }

    public void Log(string message)
    {
        writer.WriteLn(message + "Date");
    }
}

With the end result that your program code looks like this:

class Program
{
    static void Main(string[] args)
    {
        Logger logger = new Logger(new ConsoleWriter());
        logger.Log("Test");
    }
}

The benefit is that if you want to use your crazy networking protocol, you can do it without even looking at the logging class. You just have to make a new class with your IOutputWriter interface and tell your logger to use your custom backend. The strategy pattern is essentially defining reusable interfaces and then using those interfaces to decouple algorithms from each other.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top