策略模式没有“开关”语句? [英] Strategy Pattern with no 'switch' statements?

查看:172
本文介绍了策略模式没有“开关”语句?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在做的策略模式一些阅读,并有一个问题。我已经实现下面一个非常基本的控制台应用程序来解释我问。



我已阅读,有开关语句执行该战略格局的时候是红旗。不过,我似乎无法从具有在这个例子中switch语句中脱身。我缺少的东西吗?我能够从铅笔,但我的主要有一个switch语句中,现在删除的逻辑。我明白,我可以很容易地创建一个新的 TriangleDrawer 类,就不必打开铅笔类,这是很好的。不过,我需要打开主要,以便它知道哪种类型的 IDrawer 传递给铅笔。这只是需要做什么,如果我依靠用户输入?如果有办法做到这一点没有switch语句,我很想看看吧!



 类节目
{
公共类铅笔
{
私人IDraw抽屉;

公共铅笔(IDraw iDrawer)
{
抽屉= iDrawer;
}

公共无效抽奖()
{
drawer.Draw();
}
}

公共接口IDraw
{
void绘制();
}

公共类CircleDrawer:IDraw
{
公共无效抽奖()
{
Console.Write(()\ N);
}
}

公共类SquareDrawer:IDraw
{
公共无效抽奖()
{
Console.WriteLine( [] \\\
);
}
}

静态无效的主要(字串[] args)
{
Console.WriteLine(你想画什么1?圆或2:Sqaure);

INT输入;
如果(int.TryParse(到Console.ReadLine(),出输入))
{
铅笔铅笔= NULL;

开关(输入)
{
壳体1:
铅笔=新铅笔(新CircleDrawer());
中断;
案例2:
铅笔=新铅笔(新SquareDrawer());
中断;
默认:
的回报;
}

pencil.Draw();

Console.WriteLine(按任意键退出...);
Console.ReadKey();
}
}
}



显示的实施方案以下(感谢所有谁回答!)
该解决方案让我到我唯一需要做的,使用新的 IDraw 对象的一点是要创建它。

 公共类铅笔
{
私人IDraw抽屉;

公共铅笔(IDraw iDrawer)
{
抽屉= iDrawer;
}

公共无效抽奖()
{
drawer.Draw();
}
}

公共接口IDraw
{
INT ID {搞定; }
void绘制();
}

公共类CircleDrawer:IDraw
{

公共无效抽奖()
{
Console.Write( ()\\\
);
}

公众诠释ID
{
{返回1; }
}
}

公共类SquareDrawer:IDraw
{
公共无效抽奖()
{
Console.WriteLine ([] \\\
);
}

公众诠释ID
{
得到{2; }
}
}

公共静态类DrawingBuilderFactor
{
私人静态列表< IDraw>抽屉=新的List< IDraw>();

公共静态IDraw GetDrawer(INT drawerId)
{
如果(drawers.Count == 0)
{
抽屉= Assembly.GetExecutingAssembly()
.GetTypes()
。凡(类型=> typeof运算(IDraw).IsAssignableFrom(类型)及和放大器; type.IsClass)
。选择(类型=> Activator.CreateInstance (类型))
.Cast< IDraw>()
.ToList();
}

返回drawers.Where(抽屉=> drawer.ID == drawerId).FirstOrDefault();
}
}

静态无效的主要(字串[] args)
{
INT输入= 1;

,而(输入!= 0)
{
Console.WriteLine(你想吃点什么来绘制1:圆形或2:Sqaure);

如果(int.TryParse(到Console.ReadLine(),出输入))
{
铅笔铅笔= NULL;

IDraw抽屉= DrawingBuilderFactor.GetDrawer(输入);

铅笔=新铅笔(抽屉);
pencil.Draw();
}
}
}


解决方案

战略是不是一个魔抗交换机解决方案。它所做的是给modularise你的代码,这样,而不是一个大型交换机和业务逻辑都在一个维护的噩梦




    混合起来
  • 您的业务逻辑隔离,对扩展开放

  • 您有选择为你如何创建你的具体类(例如,见工厂模式)

  • 您的基础结构代码(主)可能会非常干净,无两者



有关的例子 - 如果你把开关中的主要方法,并建立了一个它接受命令行参数和返回IDraw的实例类(即它封装了开关)你的主要是再次清洁,交换机是一个类,其唯一目的是实现这样的选择。


I've been doing some reading on the Strategy Pattern, and have a question. I have implemented a very basic Console Application below to explain what I'm asking.

I have read that having 'switch' statements is a red flag when implementing the strategy pattern. However, I can't seem to get away from having a switch statement in this example. Am I missing something? I was able to remove the logic from the Pencil, but my Main has a switch statement in it now. I understand that I could easily create a new TriangleDrawer class, and wouldn't have to open the Pencil class, which is good. However, I would need to open Main so that it would know which type of IDrawer to pass to the Pencil. Is this just what needs to be done if I'm relying on the user for input? If there's a way to do this without the switch statement, I'd love to see it!

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

Implemented Solution shown below (Thanks to all who responded!) This solution got me to the point where the only thing I need to do to use a new IDraw object is to create it.

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 isn't a magic anti-switch solution. What it does do is give modularise your code so that instead of a big switch and business logic all mixed up in a maintenance nightmare

  • your business logic is isolated and open for extension
  • you have options as for how you create your concrete classes (see Factory patterns for example)
  • your infrastructure code (your main) can be very clean, free of both

For example - if you took the switch in your main method and created a class which accepted the command line argument and returned an instance of IDraw (i.e. it encapsulates that switch) your main is clean again and your switch is in a class whose sole purpose is to implement that choice.

这篇关于策略模式没有“开关”语句?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆