策略模式还是界面?

Jos*_*osh 7 design-patterns strategy-pattern c#-4.0

我正在寻找抽象一个辅助方法。该方法需要能够接收一个对象,根据对象的类型对其执行操作,并返回一个值。这样做会更好吗:

interface ICanDo
{
 string DoSomething();
}

string DoThings(ICanDo mything)
{
 return mything.DoSomething();
}
Run Code Online (Sandbox Code Playgroud)

或者最好做这样的事情:

interface IStrategy
{
 string DoSomething(object o);
}

string DoThings(object mything, IStrategy strategy)
{
 return strategy.DoSomething(mything);
}
Run Code Online (Sandbox Code Playgroud)

后者是否甚至使用策略模式,因为该策略没有内置到类中?

有没有更好的方法来做到这一点我没有想到?将策略构建到类中,为任何需要运行 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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Jac*_*son 5

如有疑问,请牢记 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");
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

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