在枚举结构上盘旋时重构和删除case语句

时间:2009-09-08 20:26:45

标签: java design-patterns refactoring polymorphism switch-statement

在自己的类中声明的枚举结构是业务逻辑类的成员变量。该枚举基本上代表了其他类的状态。

虽然我已多次重新审视这个问题,但替换或删除这些案例陈述对我来说非常令人沮丧。

几个业务逻辑方法简单地遍历枚举,并通过分配相同枚举的其他值和其他属性来更改该类的状态。

public enum MyEnum{ A,B,C,D }

业务逻辑类将此枚举作为成员:

public class BusinessLogic {

    private MyEnum CurrentSelection;
    private int propertyX;
    private int propertyY;

    public void operation1(){
        switch(CurrentSelection){
        case A: {alter propertyX this way; break;}
        case B: {alter propertyY this way; break;}
        case C: {alter propertyX that way; break;}
        case D: {alter propertyY that way; break;}
        }

    }

    public void operation2(){
        switch(CurrentSelection){
        case A: {CurrentSelection=MyEnum.B; break;}
        case B: {CurrentSelection=MyEnum.C; break;}
        ....etc
        }
    }

    public void operation3(){
        switch(CurrentSelection){
        case A: {CurrentSelection=MyEnum.D; break;}
        case B: {CurrentSelection=MyEnum.A; break;}
        ....etc
        }
    }
}

另一个客户端类将实例化业务逻辑类,初始化其属性,然后使用其操作方法。

我成功完成的操作(在SO的帮助下)将操作方法​​封装到命令模式结构中,因此我可以在没有任何case语句的情况下调用操作。 (here)。

我想我的麻烦是如何将case语句封装在我的业务逻辑类中。我怀疑我需要多态性和适当的数据结构。

重构专家建议每个case语句应该是一个通用接口的实现。但是如果我有3个方法迭代4个成员的枚举,这意味着我可能需要3个接口,每个接口有4个实现,给我12个类(加上3个接口)。那不是班级超载吗?逻辑在这3种方法中运行良好,但问题是重复的开关/案例陈述。

有没有办法重构那些switch语句,但避免了多态性名称中的无数其他类?是否有可能将迭代的枚举部分分解出来?或者只是重构的情况(逻辑在哪里)?


作为第一步,我完全删除了这些方法,让他们实现了一个简单的界面:

public interface Command {
    void execute();
}

因此,它的操作方法实现了命令接口:

public class Operation1 implements Command {

    private void doOperation1(){
        switch(CurrentSelection){
            ..all the cases here
        }       
    }

    public void execute() {
        doOperation1();
    }

}

正如我所看到的那样,它将购买我更清洁的业务逻辑类,但切换案例的痕迹仍然存在,对吗?

3 个答案:

答案 0 :(得分:1)

你可以在接口中包含所有三种方法,并且具有该接口的不同实现(每个枚举一个),并且让这个buisness类委托调用..

也用于更改状态,使操作的返回值为该公共接口,以便在调用这些方法时,调用类可以返回下一个状态的相应对象。

答案 1 :(得分:1)

要详细说明我的评论,并接近我认为rmn所说的话,你可以做以下事情:

public interface MyInterface {
    operation1(property);
    operation2(property);
    operation3(property);
}

public enum MyEnum implements MyInterface {
    A {
        operation1(property) {
            //Do Stuff
        }
        operation2(property) {
            //Do Stuff
        }
        operation3(property) {
            //Do Stuff
        }
    },
    B {
        operation1(property) {
            //Do Stuff
        }
        operation2(property) {
            //Do Stuff
        }
        operation3(property) {
            //Do Stuff
        }
    },
    C {
        operation1(property) {
            //Do Stuff
        }
        operation2(property) {
            //Do Stuff
        }
        operation3(property) {
            //Do Stuff
        }
    },
    D {
        operation1(property) {
            //Do Stuff
        }
        operation2(property) {
            //Do Stuff
        }
        operation3(property) {
            //Do Stuff
        }
    } 
}

这使得你有一个命令模式 - 即根据所选的不同元素为你工作的东西。它也类似于状态模式,尽管这里的重点是执行而不是数据或数据状态。

希望这有帮助。

答案 2 :(得分:0)

正如您可能从其他回答中猜到的那样,这是一个常见问题,并且已经被Martin Fowler编成了重构。看一下重构Replace Conditional with Polymorphism。 Joshua Kerievsky(Replace Conditional with Strategy)也进行了类似的编纂重构。