4

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

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

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

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

boolean a像这样在多个 s 中使用,function其中anotherFunctions 正在运行有关 to 的代码a。这很难理解代码和依赖关系,而且我也很难重构它,因为在anotherFunction. 重构这一点的努力可能非常高。

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

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

4

4 回答 4

7

您可以使用状态模式。根据布尔变量将状态和行为封装在单独的抽象State类中。当布尔值设置为 false 时,将状态更改为FalseState(which extends 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";
        }
    }
}

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

于 2013-05-20T10:33:46.000 回答
3

如果布尔 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 有意义,您也可以将其调整为有意义的。假设它处理已发布状态,您可以更改IfTrueIfAlreadyPublished和。IfFalseIfNotPublished

于 2013-05-21T03:07:26.680 回答
2

您提供的代码示例显然有些被截断,但在我看来,这个类的行为就像一个状态机

如果您在类中有许多布尔属性,并且它们都决定了该函数中方法的行为,那么您很快就会遇到可能性的爆炸式增长,并且代码可能会变得难以遵循 - 您最终会得到如下代码:

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

等等。

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

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

这使代码更容易一些,并迫使您考虑应用程序的状态,而不是单个布尔值。

然后,如果需要,您可以转到完整的状态机 - 大多数编程语言的互联网上都有参考实现。

于 2013-05-20T10:28:09.190 回答
2

从状态转换的角度思考逻辑是至关重要的。我会更进一步,使用枚举干净地定义您的状态。

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

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

于 2013-05-20T16:21:04.640 回答