C# 没有'的战略模式;开关';声明?
我一直在阅读战略模式,有一个问题。我在下面实现了一个非常基本的控制台应用程序来解释我的问题 我曾读到,在实施战略模式时,使用“切换”语句是一个危险信号。然而,在本例中,我似乎无法摆脱switch语句。我错过什么了吗?我可以从铅笔中删除逻辑,但是我的Main现在有一个switch语句。我知道我可以很容易地创建一个新的TriangleDrawer类,并且不必打开Pencil类,这很好。但是,我需要打开Main,以便它知道要传递给铅笔的IDrawer类型。如果我依赖用户的输入,这就是需要做的吗?如果有一种不使用switch语句的方法,我很乐意看到它C# 没有'的战略模式;开关';声明?,c#,design-patterns,dependency-injection,strategy-pattern,coding-style,C#,Design Patterns,Dependency Injection,Strategy Pattern,Coding Style,我一直在阅读战略模式,有一个问题。我在下面实现了一个非常基本的控制台应用程序来解释我的问题 我曾读到,在实施战略模式时,使用“切换”语句是一个危险信号。然而,在本例中,我似乎无法摆脱switch语句。我错过什么了吗?我可以从铅笔中删除逻辑,但是我的Main现在有一个switch语句。我知道我可以很容易地创建一个新的TriangleDrawer类,并且不必打开Pencil类,这很好。但是,我需要打开Main,以便它知道要传递给铅笔的IDrawer类型。如果我依赖用户的输入,这就是需要做的吗?如果有
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();
}
}
}
公共类铅笔
{
私人抽屉;
公共铅笔(IDraw iDrawer)
{
抽屉=iDrawer;
}
公众抽签()
{
抽屉;
}
}
公共接口IDraw
{
int ID{get;}
无效抽取();
}
公共类循环绘图程序:IDraw
{
公众抽签()
{
Console.Write(“()\n”);
}
公共整数ID
{
获取{return 1;}
}
}
公共类:IDraw
{
公众抽签()
{
Console.WriteLine(“[]\n”);
}
公共整数ID
{
获取{return 2;}
}
}
公共静态类DrawingBuilderFactor
{
私有静态列表抽屉=新列表();
公共静态IDraw GetDrawer(int-drawerId)
{
if(drawers.Count==0)
{
抽屉=Assembly.getExecutionGassembly()
.GetTypes()
.Where(type=>typeof(IDraw).IsAssignableFrom(type)和&type.IsClass)
.Select(类型=>Activator.CreateInstance(类型))
.Cast()
.ToList();
}
返回drawers.Where(drawer=>drawer.ID==drawerId).FirstOrDefault();
}
}
静态void Main(字符串[]参数)
{
int输入=1;
while(输入!=0)
{
Console.WriteLine(“你想画什么?1:Circle还是2:Sqaure”);
if(int.TryParse(Console.ReadLine(),out输入))
{
铅笔=空;
IDraw drawer=DrawingBuilderFactor.GetDrawer(输入);
铅笔=新铅笔(抽屉);
铅笔画();
}
}
}
策略不是神奇的反切换解决方案。它所做的是给代码模块化,这样就不用在维护噩梦中把大开关和业务逻辑混在一起了
- 您的业务逻辑是独立的,可以扩展
- 您可以选择如何创建具体的类(例如,请参见工厂模式)
- 您的基础结构代码(主代码)可以非常干净,没有这两种代码
例如,如果您在main方法中使用开关,并创建了一个接受命令行参数并返回IDraw实例的类(即,它封装了该开关)你的main又变干净了,你的switch所在的类的唯一目的就是实现这个选择。我不认为你在演示应用程序中的switch实际上是策略模式本身的一部分,它只是用来执行你定义的两个不同策略
“开关是一面红旗”警告是指在策略中有开关;例如,如果您定义了一个策略“GenericDrawer”,并让它使用参数值的开关确定用户在内部是否需要SquareDrawer或CircleDrawer,您不会从策略模式中获益。以下是针对您的问题的过度设计的解决方案,完全是为了避免
if
/switch
语句
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");
}
CircleFactory:IDrawFactory
{
字符串键{get;}
IDraw Create();
}
三角工厂:IDrawFactory
{
字符串键{get;}
IDraw Create();
}
绞车
{
列出工厂{get;}
IDraw创建(字符串键)
{
var factory=Factories.FirstOrDefault(f=>f.Key.Equals(Key));
如果(工厂==null)
抛出新ArgumentException();
返回factory.Create();
}
}
void Main()
{
DrawFactory工厂=新的DrawFactory();
工厂。创建(“圆”);
}
你也可以借助字典摆脱如果
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();
Dictionary drawFactories=new Dictionary(){{“circle”,f=>new CircleDraw()},{“square”,f=>new SquareDraw()}}();
Func工厂;
drawFactories.TryGetValue(“圆圈”,出厂);
IDraw draw=工厂();
有点晚了,但是对于那些仍然对完全删除条件语句感兴趣的人来说
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");
}
}
类程序
{
懒字典=新懒字典(
() =>
新字典()
{
{Enum.StrategyA,()=>{returnnewstrategya();}},
{Enum.StrategyB,()=>{返回新的StrategyB();}
}
);
战略"战略,;
IStrategy客户端(枚举菜单)
{
Func _Func
if(dictionary.Value.TryGetValue(enu,out\u func))
{
_策略=\u f