我有一些我想要重构的代码。我有很多方法采用相同类型的多个参数,例如:
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 ...?!
谢谢!
答案 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所说的代码气味。