c# - 没有 'switch' 语句的策略模式?

标签 c# design-patterns dependency-injection strategy-pattern coding-style

我一直在阅读有关策略模式的一些资料,并且有一个问题。我在下面实现了一个非常基本的控制台应用程序来解释我的要求。

我读到过,在实现策略模式时,使用“switch”语句是一个危险信号。但是,在这个例子中我似乎无法避免使用 switch 语句。我错过了什么吗?我能够从 Pencil 中删除逻辑,但我的 Main 现在有一个 switch 语句。我知道我可以轻松地创建一个新的 TriangleDrawer 类,而不必打开 Pencil 类,这很好。但是,我需要打开 Main 以便它知道要将哪种类型的 IDrawer 传递给 Pencil。如果我依赖用户输入,这是否正是需要做的事情?如果有一种无需 switch 语句即可执行此操作的方法,我很乐意看到它!

class Program
{
    public class Pencil
    {
        private IDraw drawer;

        public Pencil(IDraw iDrawer)
        {
            drawer = iDrawer;
        }

        public void Draw()
        {
            drawer.Draw();
        }
    }

    public interface IDraw
    {
        void Draw();
    }

    public class CircleDrawer : IDraw
    {
        public void Draw()
        {
            Console.Write("()\n");
        }
    }

    public class SquareDrawer : IDraw
    {
        public void Draw()
        {
            Console.WriteLine("[]\n");
        }
    }

    static void Main(string[] args)
    {
        Console.WriteLine("What would you like to draw? 1:Circle or 2:Sqaure");

        int input;
        if (int.TryParse(Console.ReadLine(), out input))
        {
            Pencil pencil = null;

            switch (input)
            {
                case 1:
                    pencil = new Pencil(new CircleDrawer());
                    break;
                case 2:
                    pencil = new Pencil(new SquareDrawer());
                    break;
                default:
                    return;
            }

            pencil.Draw();

            Console.WriteLine("Press any key to exit...");
            Console.ReadKey();
        }
    }
}

实现的解决方案如下所示(感谢所有响应者!) 这个解决方案让我明白,要使用新的 IDraw 对象,我唯一需要做的就是创建它。

public class Pencil
    {
        private IDraw drawer;

        public Pencil(IDraw iDrawer)
        {
            drawer = iDrawer;
        }

        public void Draw()
        {
            drawer.Draw();
        }
    }

    public interface IDraw
    {
        int ID { get; }
        void Draw();
    }

    public class CircleDrawer : IDraw
    {

        public void Draw()
        {
            Console.Write("()\n");
        }

        public int ID
        {
            get { return 1; }
        }
    }

    public class SquareDrawer : IDraw
    {
        public void Draw()
        {
            Console.WriteLine("[]\n");
        }

        public int ID
        {
            get { return 2; }
        }
    }

    public static class DrawingBuilderFactor
    {
        private static List<IDraw> drawers = new List<IDraw>();

        public static IDraw GetDrawer(int drawerId)
        {
            if (drawers.Count == 0)
            {
                drawers =  Assembly.GetExecutingAssembly()
                                   .GetTypes()
                                   .Where(type => typeof(IDraw).IsAssignableFrom(type) && type.IsClass)
                                   .Select(type => Activator.CreateInstance(type))
                                   .Cast<IDraw>()
                                   .ToList();
            }

            return drawers.Where(drawer => drawer.ID == drawerId).FirstOrDefault();
        }
    }

    static void Main(string[] args)
    {
        int input = 1;

        while (input != 0)
        {
            Console.WriteLine("What would you like to draw? 1:Circle or 2:Sqaure");

            if (int.TryParse(Console.ReadLine(), out input))
            {
                Pencil pencil = null;

                IDraw drawer = DrawingBuilderFactor.GetDrawer(input);

                pencil = new Pencil(drawer); 
                pencil.Draw();
            }
        }
    }

最佳答案

Strategy 并不是一种神奇的反转换解决方案。它所做的是对您的代码进行模块化,这样就不会在维护噩梦中混合使用大的开关和业务逻辑

  • 您的业务逻辑是独立的并且可以扩展
  • 您可以选择如何创建具体类(例如,参见工厂模式)
  • 您的基础架构代码(您的主代码)可以非常干净,两者都没有

例如 - 如果您在 main 方法中使用了开关并创建了一个接受命令行参数并返回 IDraw 实例的类(即它封装了该开关)您的 main 再次干净并且您的开关在一个类中其唯一目的是实现该选择。

关于c# - 没有 'switch' 语句的策略模式?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3834091/

相关文章:

C# 并行更新字典的条目?

c# - BindingExpression 路径错误 : property not found on 'object'

c# - Windows Metro 应用程序中缺少 XPath

design-patterns - IRepository 接口(interface)属于哪里?

java - Camel @BeanInject 在蓝图测试中不起作用

c# - 未找到单声道 MissingMethodException : DateTimeOffset. FromUnixTimeSeconds

design-patterns - 使用与域实体的一对一接口(interface)是好的还是坏的做法?为什么?

保存/加载其状态的 JavaScript 对象

.net - 构造函数注入(inject) - 在哪里调用?

angular - 如何使用工厂供应商?