Strategy Pattern with no 'switch' statements?

柔情痞子 提交于 2019-11-28 15:28:28
brabster

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.

Muhammad Hasan Khan

The following is an over engineered solution to your problem solely for the sake of avoiding if/switch statements.

CircleFactory: IDrawFactory
{
  string Key { get; }
  IDraw Create();
}

TriangleFactory: IDrawFactory
{
  string Key { get; }
  IDraw Create();
}

DrawFactory
{
   List<IDrawFactory> Factories { get; }
   IDraw Create(string key)
   {
      var factory = Factories.FirstOrDefault(f=>f.Key.Equals(key));
      if (factory == null)
          throw new ArgumentException();
      return factory.Create();
   }
}

void Main()
{
    DrawFactory factory = new DrawFactory();
    factory.Create("circle");
}

I don't think your switch here in your demo app is actually part of the strategy pattern itself, it is just being used to exercise the two different strategies you have defined.

The "switches being a red flag" warning refers to having switches inside the strategy; for example, if you defined a strategy "GenericDrawer", and had it determine if the user wanted a SquareDrawer or CircleDrawer internally using a switch against a parameter value, you would not be getting the benefit of the strategy pattern.

Muhammad Hasan Khan

You can also get rid of if with help of a dictionary

Dictionary<string, Func<IDraw> factory> drawFactories = new Dictionary<string, Func<IDraw> factory>() { {"circle", f=> new CircleDraw()}, {"square", f=> new SquareDraw()}}();

Func<IDraw> factory;
drawFactories.TryGetValue("circle", out factory);

IDraw draw = factory();

A little to late but for anyone that still is interested in fully removing a conditional statement.

     class Program
     {
        Lazy<Dictionary<Enum, Func<IStrategy>>> dictionary = new Lazy<Dictionary<Enum, Func<IStrategy>>>(
            () =>
                new Dictionary<Enum, Func<IStrategy>>()
                {
                    { Enum.StrategyA,  () => { return new StrategyA(); } },
                    { Enum.StrategyB,  () => { return new StrategyB(); } }
                }
            );

        IStrategy _strategy;

        IStrategy Client(Enum enu)
        {
            Func<IStrategy> _func
            if (dictionary.Value.TryGetValue(enu, out _func ))
            {
                _strategy = _func.Invoke();
            }

            return _strategy ?? default(IStrategy);
        }

        static void Main(string[] args)
        {
            Program p = new Program();

            var x = p.Client(Enum.StrategyB);
            x.Create();
        }
    }

    public enum Enum : int
    {
        StrategyA = 1,
        StrategyB = 2
    }

    public interface IStrategy
    {
        void Create();
    }
    public class StrategyA : IStrategy
    {
        public void Create()
        {
            Console.WriteLine("A");
        }
    }
    public class StrategyB : IStrategy
    {
        public void Create()
        {
            Console.WriteLine("B");
        }
    }
IReadOnlyDictionaru<SomeEnum, Action<T1,T2,T3,T3,T5,T6,T7>> _actions 
{
    get => new Dictionary<SomeEnum, Action<T1,T2,T3,T3,T5,T6,T7>> 
        {
           {SomeEnum.Do, OptionIsDo},
           {SomeEnum.NoDo, OptionIsNoDo}
        } 
}

public void DoSomething(SomeEnum option)
{
    _action[option](1,"a", null, DateTime.Now(), 0.5m, null, 'a'); // _action[option].Invoke(1,"a", null, DateTime.Now(), 0.5m, null, 'a');
}


pub void OptionIsDo(int a, string b, object c, DateTime d, decimal e, object f, char c)
{
   return ;
}

pub void OptionIsNoDo(int a, string b, object c, DateTime d, decimal e, object f, char c)
{
   return ;
}

In case you don't need polymorphism. The example uses Action but any other delegate type can be passed in. Func if you want to return something

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!