避免使用布尔标志作为属性

时间:2013-05-20 10:15:19

标签: design-patterns refactoring boolean

首先,我想说我在重构方面没有太多经验,也不知道这是否是偏离主题的。

我正在使用给定代码,其中使用了许多布尔属性,由于可读性,我想避免使用它,而且我不知道如何以正确的方式处理它。

class MyClass(){
    boolean a;
    ...
    void function(){
        ...
        a = true;
        ...
    }

    void anotherFunction(){
        ...
        if(a == true){
            //do something
        } else {
            //do something else
        }
        ...
    }
    ...
}

boolean a用于多个function,其中anotherFunction正在运行与a相关的代码。由于在anotherFunction中使用了多个属性和局部变量,因此很难理解代码和依赖关系,而且我很难重构它。重构的努力可能非常高。

我总是试图避免使用这样的布尔值,因为在我看来这不是一个好习惯。如果我错了,请不要犹豫,纠正我。

现在我想知道我是否应该重构代码并花费精力?在这种情况下是否可以使用某种模式?

4 个答案:

答案 0 :(得分:6)

您可以使用状态模式。根据单独的抽象State类中的布尔变量封装状态和行为。当布尔值设置为false时,将状态更改为FalseState(扩展State)的实例,并委托给此FalseState实例。当布尔值设置为true时,将状态更改为TrueState的实例,并委托给此TrueState实例。

例如,以下类

public class Apple {

    private boolean fresh = false;

    public String getColor() {
        if (fresh) {
            return "green";
        }
        else {
            return "brown";
        }
    }

    public void setFresh(boolean fresh) {
        this.fresh = fresh;
    }
}

可以重构为

public class Apple {

    private AppleState state = new OldAppleState();

    public String getColor() {
        return state.getColor();
    }

    public void setFresh(boolean fresh) {
        this.state = state.nextState(fresh);
    }

    private static abstract class State {
        public abstract State nextState(boolean fresh);
        public abstract String getColor();
    }

    private static class OldAppleState extends State{
        public State nextState(boolean fresh) {
            return fresh ? new FreshAppleState() : this;
        }
        public String getColor() {
            return "brown";
        }
    }


    private static class FreshAppleState extends State{
        public State nextState(boolean fresh) {
            return fresh ? this : new OldAppleState();
        }
        public String getColor() {
            return "green";
        }
    }
}

我使用了内部类,但你当然可以使用顶级类。

答案 1 :(得分:2)

您提供的代码示例显然有些截断,但我觉得这个类的行为类似于state machine

如果类中有许多布尔属性,并且它们都确定了该函数中方法的行为,那么很快就会出现大量可能性,并且代码变得难以理解 - 最终会得到代码像:

if (true == a && false == b){
   ...
}
elseif (false == a && false == b){
   ....
}

等等。

您可以应用的第一个重构是创建状态查找方法;这会将上面的代码转换为:

if (aNotB == getState(a, b)){
   ....
}
elseif (notANotB == getState(a, b)){
   ...
}

这使得代码变得更容易,并迫使您根据应用程序的状态进行思考,而不是单个布尔值。

如果需要,您可以转到完整的状态机 - 对于大多数编程语言,遍布整个网络的参考实现。

答案 2 :(得分:2)

如果多次使用布尔a,我更喜欢类似monad的内部类函数。

public class BoolAHandler{
    public bool A = false;
    public BoolAHandler IfTrue(Action act){
        if(A){
            act();
        }
        return this;
    }
    public BoolAHandler IfFalse(Action act){
        if(!A){
            act();
        }
        return this;
    }
}

用法:

boolAHandler.IfTrue( () => { doFunctionA(); } )
            .IfFalse( () => { doFunctionB(); } );

当然,如果布尔a有意义,你也可以调整它的含义。如果它处理已发布状态,您可以将IfTrue更改为IfAlreadyPublished,将IfFalse更改为IfNotPublished

答案 3 :(得分:1)

考虑国家转型的逻辑至关重要。我会更进一步,使用枚举清晰地定义你的状态。

public enum AppState { 
    ST1(false, false), 
    ST2(false, true),
    ST3(true, false), 
    ST4(true, true);
    private Boolean x, y;
}

使用枚举的一个特别有用的优点是能够定义模板方法 - Template methods using enums。将让您简化您的功能以匹配您的状态,并使其更加面向对象。