在对象中包装布尔值

时间:2009-09-10 14:48:58

标签: java refactoring

我有一些我想要重构的代码。我有很多方法采用相同类型的多个参数,例如:

public void foo(String name, String street, boolean b1, boolean b2) { ... }

等等。因为不同的对象只能通过名称来区分,所以我想将它们包装在Objects(Enums)中,这样我就可以使用该语言的类型系统(在本例中为Java)。

public class Name {
    private String value;
    public String getValue() { return value; }
    // ...
}

像这样我可以强制调用代码传递某种类型的对象。这样可以确保它不会意外地混淆方法参数的顺序,因此不会在运行时产生意外行为

foo(new Name("John"), new Street("Broadway"), new B1(true), new B2(false);

这使得重构更加安全,只要你愿意,你可以通过系统携带对象,其中的数据,字符串始终是安全的。 只有在您需要时,才能通过调用getValue()获得它。

现在,对于包装字符串的对象,它非常简单,因为有许多状态实例可以存在。

但布尔包装器怎么样?这些是TRUE或FALSE。这个实现看起来很有趣:

public enum Quanto {

    YES() {
        protected boolean isQuanto() {
            return true;
        }
    },
    NO() {
        protected boolean isQuanto() {
            return false;
        }
    };

    protected abstract boolean isQuanto();

}

更奇怪的是我发现调用代码是什么样的:

public void doStuff(Quanto quanto) {
    if(quanto.isQuanto()) {
        // ...
    }
}

从技术上讲,这当然没关系,但感觉不对......你找到了“更好”的方法来解决这个问题吗?

编辑:令我不高兴的是,在上面的例子中,有比 YES NO 更多的值可以理解,比如说< STRONG> MAYBE ...?!

谢谢!

4 个答案:

答案 0 :(得分:9)

我会将布尔值换成语义枚举。换句话说:

public void doStuff(boolean isActive, boolean wrapResult);

变为

public enum State {ACTIVE, INACTIVE};
public enum ResultMode {WRAPPED, UNWRAPPED};

public void doStuff(State state, ResultMode resultsMode);

答案 1 :(得分:4)

基本上你正在做的是命名参数,所以我建议每个函数使用一个类,每个参数都有成员。

呼叫站点看起来像这样:

foo(new foo_arguments().Name("John").Street("Broadway").B1(true).B2(false));

然后你在函数内部使用arguments.Name()等。

这还有一个额外的好处,就是让你在没有大量重载的情况下给出默认参数,并允许以任何顺序指定参数,所以这可行:

foo(new foo_arguments().Street("Sesame").Name("Monster"));

所需的课程:

public class foo_arguments {
    private string _name = "John Doe";
    public foo_arguments Name(string name) { _name = name; return this; }
    public string Name() { return _name; }

    private string _street = "Pennsylvania Ave NW";
    public foo_arguments Street(string street) { _street = street; return this; }
    public string Street() { return _street; }

    private string _b1 = false;
    public foo_arguments B1(string b1) { _b1 = b1; return this; }
    public boolean B1() { return _b1; }

    private string _b2 = true;
    public foo_arguments B2(string b2) { _b2 = b2; return this; }
    public boolean B2() { return _b2; }
}

顺便说一句,在C#中,您可以使用自动属性和对象初始化器来优雅地完成此任务。

答案 2 :(得分:2)

这些方法总是采用相同的参数集吗?如果他们这样做,您可能想要创建一个存储所有数据的数据对象,并且您只将该对象提供给函数。也许您甚至可以在以后将函数移动到对象中。 拥有许多输入参数的方法有时会提示缺少所有这些参数的对象。

我不想在一个对象中封装一个布尔值。这似乎不适合我。

答案 3 :(得分:1)

为什么不为你传递给方法的不同值设置封装对象,而不是为布尔值设置枚举?这样,值就会出现在getter和setter上,并且拥有您想要的信息:

public class Encapsulator {

    private boolean isSelected;
    private boolean isAwake;


    public boolean isAwake() {
        return isAwake;
    }

    public void setIsAwake(boolean isAwake) {
        this.isAwake = isAwake;
    }

    public boolean isSelected() {
        return isSelected;
    }

    public void setIsSelected(boolean isSelected) {
        this.isSelected = isSelected;
    }
}

这样,当您访问数据时,很明显对象中的特定元素会做一件事或另一件事。它还减少了方法的参数集,这是Martin Fowler所说的代码气味。