Not*_*sxl 2 c# polymorphism enums design-patterns visitor-pattern
如果我们想要将枚举(包含在域层中)重构为多态类,那么使用"简单"抽象方法可能是一个坏主意,如果我们要重构的所有switch和if语句都在其他层内(如业务或表示层),因为我们最终可能会在域层内引用这些层:
public abstract class MyRefactoredEnum
{
public abstract void DoSomething(IBusinnessObject aBizObject); //dependency to the biz. layer
public abstract MvcHtmlString GetImgTag(); //dependency to presentation layer
}
Run Code Online (Sandbox Code Playgroud)
(在上面的例子中,我们也可以有一个"交叉引用"问题)
我发现访问者模式(http://en.wikipedia.org/wiki/Visitor_pattern)是这个问题的有效解决方案:在域层我们只定义了MyRefactoredEnum.IVisitor接口,所有其他层都可以实施自己的访客.
唯一的问题是:当我们修改MyRefactoredEnum.IVisitor接口时(例如,因为我们添加了另一个MyRefactoredEnum的子类),我们必须修改并重新编译引用域模型的所有项目和解决方案.我们可以使用反射来解决问题(http://surguy.net/articles/visitor-with-reflection.xml),但它可能很慢......
重构枚举是否有更好的模式?
PS:对不起我糟糕的英语:)
您可以为具有后备方法的访问者提供默认实现:
abstract class Cheese
{
public abstract void Visit(ICheeseVisitor visitor);
}
class Wensleydale : Cheese { ... }
class Gouda : Cheese { ... }
interface ICheeseVisitor
{
void Visit(Wensleydale cheese);
void Visit(Gouda cheese);
}
abstract class CheeseVisitor : ICheeseVisitor
{
public virtual void Visit(Wensleydale cheese) { Default(cheese); }
public virtual void Visit(Gouda cheese) { Default(cheese); }
public virtual void Default(Cheese cheese) { }
}
Run Code Online (Sandbox Code Playgroud)
添加新类型时,针对旧版本构建的库将使用fall-back方法,而较新的库可以覆盖新的重载:
class Brie
{
public override void Visit(ICheeseVisitor visitor)
{
visitor.Visit(this);
}
}
interface ICheeseVisitor
{
...
void Visit(Brie cheese);
}
abstract class CheeseVisitor : ICheeseVisitor
{
...
public virtual void Visit(Brie cheese) { Default(cheese); }
...
}
Run Code Online (Sandbox Code Playgroud)
例:
class CheeseImgVisitor : CheeseVisitor
{
private string src;
public string Src
{
get { return this.src; }
}
public override void Visit(Wensleydale cheese)
{
this.src = "wensleydale.png";
}
public override void Visit(Gouda cheese)
{
this.src = "gouda.png";
}
public override void Default(Cheese cheese)
{
this.src = "generic_cheese.png";
}
}
Run Code Online (Sandbox Code Playgroud)