总是避免Java中的输入输出参数?
毫无疑问,输入输出参数会导致代码混淆,因为它们可能会增加意外/不可预测的副作用。总是避免Java中的输入输出参数?
所以,很多优秀的程序员说:
避免在出参数变化的可变方法的参数。倾向于保持参数不变。
对于期望他的代码是最干净和可理解的完美主义程序员来说,这个“规则”是否必须适用于所有情况?
例如,假设一个基本的方法将元素添加到一个简单的列表,有两种方式:
第一种方式(与IN-OUT参数):
private void addElementsToExistingList(List<String> myList){
myList.add("Foo");
myList.add("Bar");
}
,主叫方是:
List<String> myList = new ArrayList<String>();
//.......Several Instructions (or not) .....
addElementsToExistingList(myList);
没有out参数方式二:
private List<String> addElementsToExistingList(List<String> originalList){
List<String> filledList = new ArrayList<String>(originalList); //add existing elements
filledList.add("Foo");
filledList.add("Bar");
return filledList;
}
和呼叫者的存在:
的第二方式List<String> myList = new ArrayList<String>();
//.......Several Instructions (or not) .....
myList.addAll(addElementsToExistingList(myList));
优点:
参数不被修改=>无的意想不到的副作用为一个新的代码读取器的危险。
缺点的第二种方式:
非常详细,非常不易阅读...
当然,你会告诉我,因为这样做有一个简单代码,第一种方式是真的方便多了。但是,如果我们不考虑任何概念/代码的难度,我会对任何读者(不管是否是初学者)的第二种方式更合乎逻辑和明显。
但是,它违反了CQS原则,认为具有返回类型且没有副作用的具有无效返回潜在(但允许,因为它是约定)副作用的“命令”方法和“查询”方法。
那么,一个激励程序员应该采用什么?两种符合代码情况的混合?或者保持“法律”期望始终避免输入参数...
(当然,添加元素的方法是为了解释示例而命名的,并且在实际代码中是错误的名称选择)。
我认为法律应该是:
用的是更直接的,但总是,总是文档你的方法广泛的行为。
你的第二个例子是一个非常好的情况下没有证件,你将有保证的缺陷:该方法的名称为addElementsToExistingList
,但不元素添加到现有列表的方法 - 它创建一个新的。一个反直觉和误导性的名字,至少可以说...
在你的例子中,名称明确表示 - “addElementsToExistingList”对我来说似乎很清楚,暗示你将要.. er .. 你懂。但是你的担心可以用一个不太明显的名字来证明。
例如,在红宝石这通常与命名约定
"a".upcase
=>为您提供了变量的大写,离开原来的不变 "a".upcase!
=>改变处理的原始变量
除了一点细节:*提示*在第二个片段中完全错误,因为现有列表未被修改:-) – thkala 2012-03-12 20:09:32
它的优良只要有文件记载,就可以改变/改变参数。当然,使用方法名称“addElementsToExistingList”,还应该指望什么?然而,正如有人以前指出的,你的第二个实现返回一个副本,并且不会修改原始的,所以方法名现在是误导性的。你的第一个方法是完全可以接受的做事方式。唯一的其他改进是如果仅将所有元素添加到列表中,则可能向返回值添加true/false值以指示true。
还有第三种方法。裹List<String>
到知道如何将元素添加到自己的类:
class ElementList {
private List<String> = new ArrayList<String>();
public void addElements(Element... elements);
}
我喜欢这种方法,因为它使List
实现私有。如果有人将不可变列表传递给您的方法或参数是否已修改,则不必担心。代码更简单。像addElementsToExistingList
这样的长方法名称是代码的气味,对象正在尝试做另一个对象应该做的事情。
当变异作为参数的对象时,您应该始终记录文档,否则这可能会给调用者带来意想不到的副作用。在第一种情况下,我同意其他评论说方法名称是足够的文档。
在你的第二个例子中,已经出现在myList中的元素似乎被添加了两次。事实上,你可以完全移除addElementsToExistingList方法的参数,它改写为:
private List<String> getElements() {
List<String> filledList = new ArrayList<String>();
filledList.add("Foo");
filledList.add("Bar");
return filledList;
}
List<String> myList = new ArrayList<String>();
//.......Several Instructions (or not) .....
myList.addAll(getElements());
注意,该代码不等同于你的第二个例子,因为该元素只加一次,但我认为这实际上是什么你打算。这是我通常喜欢的风格。此代码比第一个示例更容易理解并且更灵活,无需添加额外的代码(它可能会使性能略有下降,但这通常不是问题)。除了将元素列表添加到现有集合之外,getElements()的客户端现在还可以使用元素列表完成其他事情。
我非常同意你的看法,但它代表了一些非常受欢迎的方法(非实验总是这样做):)事实上,我读了很多类似的方法, – Mik378 2012-03-12 19:54:55