我有一个界面和3个功能
public interface IDrawingObject
{
void Draw(Color c);
}
public class DrawTriangle : IDrawingObject
{
public void Draw(Color c)
{
//for demo purpose
Console.WriteLine("Drawing Triangle with color " + c.Name );
}
}
public class DrawCircle : IDrawingObject
{
public void Draw(Color c)
{
//for demo purpose
Console.WriteLine("Drawing Circle with color " + c.Name);
}
}
public class DrawRectangle : IDrawingObject
{
public void Draw(Color c)
{
//for demo purpose
Console.WriteLine("Drawing Rectangle with color " + c.Name);
}
}
和这个枚举
public enum Shapes
{
Circle,
Rectangle,
Triangle
}
这里可以有更多的功能(和枚举)
我想让static void Draw(Shapes s, Color c)
根据此枚举选择要调用的正确函数,并且在我看来,使用if-else(或switch将使代码膨胀)
所以我采用了另一种方法,即使用IDictionary
private static IDictionary<Shapes, Action<Color>> Mapper = new Dictionary<Shapes, Action<Color>>
{
{ Shapes.Circle, (Color c) => { IDrawingObject draw = new DrawTriangle(); draw.Draw(c);} },
{ Shapes.Rectangle, (Color c) => { IDrawingObject draw = new DrawRectangle(); draw.Draw(c); } },
{ Shapes.Triangle, (Color c) => { IDrawingObject draw = new DrawCircle(); draw.Draw(c); } }
};
我的功能是
public static void Draw(Shapes s, Color c)
{
if (Mapper.ContainsKey(s))
{
Mapper[s](c);
}
}
但是,在我看来,我仍在进行大量不复杂的复制和粘贴
还有更好的方法吗?
PS
答案 0 :(得分:1)
虽然我不建议这样做,但是您可以使用反射通过名称创建类的实例。像这样(未经测试):
var draw = (IDrawingObject)Activator.CreateInstance("AssemblyName", "Draw" + shape.ToString());
draw.Draw();
答案 1 :(得分:1)
此代码并不是真的比switch
干净,除非字典被多种方法使用。使用绘图对象和界面的方式,所有Draw
方法都可以很容易地在一个类上成为静态方法。
回答了确切的问题,可以使用Dictionary.TryGetValue
:
public static void Draw(Shapes s, Color c)
{
if (Mapper.TryGetValue(s,out var act))
{
act(c);
}
}
所有Draw
方法都可以更改为静态方法,因为它们不使用任何实例成员:
private static IDictionary<Shapes, Action<Color>> Mapper = new Dictionary<Shapes, Action<Color>>
{
[Shapes.Circle]= (Color c) => DrawTriangle.Draw(c),
[Shapes.Rectangle]= (Color c) => DrawRectangle.Draw(c),
[Shapes.Triangle]=(Color c) => DrawCircle.Draw(c)
};
如果不是:
private static IDictionary<Shapes, Action<Color>> Mapper = new Dictionary<Shapes, Action<Color>>
{
[Shapes.Circle] = DrawTriangle.Draw,
[Shapes.Rectangle] = DrawRectangle.Draw,
[Shapes.Triangle] = DrawCircle.Draw
};
更新
语法显示的顺便说一句,这有点奇怪。使用 types 代替枚举会阻止在请求圆时绘制圆
我们需要更多地了解Shapes
的来源,或者为什么要使用接口来创建更好的实现,并且要避免使用错误的实现
顺便说一句,可以将C#8的switch表达式与接口一起使用:
var drawer= shapes switch
{
Shapes.Circle =>new DrawingTriangle(),
Shapes.Rectangle=>new DrawingRectangle(),
Shapes.Triangle =>new DrawingCircle(),
_ => ???
};
drawer.Draw(c);
答案 2 :(得分:1)
看看您的Draw
方法:它们实际上是否对DrawTriangle
,DrawRectangle
等类中的任何类进行了更改?
如果没有,那么您不需要每次想绘制东西时都创建一个新实例。相反,您可以只将DrawTriangle
的一个实例存储在Mapper
字典中:
private static Dictionary<Shapes, IDrawingObject> Mapper = new Dictionary<Shapes, IDrawingObject>()
{
{ Shapes.Circle, new DrawCircle() },
{ Shapes.Rectangle, new DrawRectangle() },
{ Shapes.Triangle, new DrawTriangle() },
};
然后,您为给定的IDrawingObject
获取相应的Shapes
,并调用其Draw
方法:
public static void Draw(Shapes s, Color c)
{
if (Mapper.TryGetValue(s, out IDrawingObject drawingObject))
{
drawingObject.Draw(c);
}
}
如果出于某些原因要做需要在您要绘制三角形时立即创建一个新的DrawTriangle
,则可以将Func<IDrawingObject>
个委托放入字典中,但是仍以您的静态IDrawingObject.Draw
方法调用Draw
:
private static Dictionary<Shapes, Func<IDrawingObject>> Mapper = new Dictionary<Shapes, IDrawingObject>()
{
{ Shapes.Circle, () => new DrawCircle() },
{ Shapes.Rectangle, () => new DrawRectangle() },
{ Shapes.Triangle, () => new DrawTriangle() },
};
然后:
public static void Draw(Shapes s, Color c)
{
if (Mapper.TryGetValue(s, out Func<IDrawingObject> drawingObjectFactory))
{
IDrawingObject drawingObject = drawingObjectFactory();
drawingObject.Draw(c);
}
}
答案 3 :(得分:0)
这实际上就是您所拥有的!
您可以使用扩展方法使讨厌的枚举看起来像“适当”的对象。 (虽然是一个海市rage楼,但在MkShape方法中具有异常)。
所以对此的主要反对意见是它不是类型安全的,如果您添加新的枚举并忘记更新MkShape,您的代码将崩溃...像F#,Scala等这样的功能性语言会警告您这很糟糕。 / p>
您的字典什么也没做,只是交换一点复杂性以换取switch语句的微小性能优势...即除非您有数百个枚举值,否则不要打扰,它甚至可能会降低性能(对于较小的n)
public enum Shapes
{
Circle,
Rectangle,
Triangle
}
public interface IShape
{
void Draw(Color c);
}
public static class Shape
{
public static void ExampleClientCode()
{
var s = Shapes.Circle;
// your enum looks like a "proper" object
s.Draw(Color.AliceBlue);
}
public static IShape MkShape(this Shapes s)
{
switch (s)
{
case Shapes.Circle:
return new Circle();
case Shapes.Rectangle:
return new Rectangle();
case Shapes.Triangle:
return new Triangle();
default:
throw new Exception("nasty enum means I can't have typesafe switch statement");
}
}
public static void Draw(this Shapes s,Color c)
{
s.MkShape().Draw(c);
}
}
public class Triangle : IShape
{
public void Draw(Color c)
{
//for demo purpose
Console.WriteLine("Drawing Triangle with color " + c.Name);
}
}
public class Circle : IShape
{
public void Draw(Color c)
{
//for demo purpose
Console.WriteLine("Drawing Circle with color " + c.Name);
}
}
public class Rectangle : IShape
{
public void Draw(Color c)
{
//for demo purpose
Console.WriteLine("Drawing Rectangle with color " + c.Name);
}
}
P.S。
我怀疑将颜色存储在形状中可能很有用,但是如果您绑定到枚举,那么您将只知道形状而不是其他任何东西