2

如果我们想将枚举(包含在域层中)重构为多态类,那么使用“简单”抽象方法可能不是一个好主意,如果我们想要重构的所有 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:对不起我糟糕的英语:)

4

1 回答 1

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";
    }
}
于 2010-08-28T12:43:26.730 回答