如果我们想要将枚举(包含在域层中)重构为多态类,那么使用“简单”抽象方法可能是个坏主意,如果我们要重构的所有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
}
(在上面的示例中,我们也可以有“交叉引用”问题)
我发现访问者模式(http://en.wikipedia.org/wiki/Visitor_pattern)是这个问题的有效解决方案:在域层我们只定义了MyRefactoredEnum.IVisitor接口,所有其他层都可以实现自己的访问者。
唯一的问题是:当我们修改MyRefactoredEnum.IVisitor接口时(例如,因为我们添加了另一个MyRefactoredEnum的子类),我们必须修改并重新编译引用域模型的所有项目和解决方案。我们可以使用反射(http://surguy.net/articles/visitor-with-reflection.xml)解决问题,但它可能很慢......
重构枚举是否有更好的模式?
PS:对不起我糟糕的英语:)
答案 0 :(得分:5)
您可以为具有后备方法的访问者提供默认实现:
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) { }
}
添加新类型时,针对旧版本构建的库将使用后备方法,而较新的库可以覆盖新的重载:
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); }
...
}
示例:
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";
}
}