战略模式还是界面?

时间:2013-02-25 06:06:31

标签: c#-4.0 design-patterns strategy-pattern

我正在寻找一个帮助方法。该方法需要能够接受一个对象,根据对象的类型对它做一些事情,并返回一个值。做这样的事情会更好:

interface ICanDo
{
 string DoSomething();
}

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

或者做这样的事情会更好:

interface IStrategy
{
 string DoSomething(object o);
}

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

后者是否甚至使用策略模式,因为策略没有被构建到类中?

有没有更好的方法来做到这一点我没想到?将策略构建到类中是否更好,使用需要在其上运行DoThings的任何类的包装器?

抱歉 - 我是这个模式的新手,并试图找出最佳使用方式和位置。

这就是我最终整理的内容。我不确定这是否符合良好的发展原则。

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);
        }
    }
}

1 个答案:

答案 0 :(得分:2)

如果有疑问,请记住KISS的口头禅 - 保持简短。模式可能非常有用,但通常它们仅在特定情况下有用,否则会增加不必要的复杂性

根据我的经验,当您有多个不同的后端可供选择时,策略模式非常有用。例如,假设您有一个程序用来打印调试信息的日志类。在某些情况下,您可能希望登录到文件。也许你想登录到控制台。也许你甚至想用你公司制作的专有协议登录远程服务器!

因此,您的日志记录类可能如下所示:

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");
    }
}

最终结果是您的程序代码如下所示:

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

好处是,如果您想使用疯狂的网络协议,您甚至无需查看日志记录类就可以实现。您只需使用IOutputWriter接口创建一个新类,并告诉您的记录器使用您的自定义后端。策略模式实质上是定义可重用接口,然后使用这些接口将解耦算法相互连接。