2012-03-12 4 views
3

予期しない/予期しない副作用を増やす可能性があるため、in-outパラメータが混乱したコードにつながることは間違いありません。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)); 

長所:

パラメータは、新しいコード・リーダのための予期しない副作用の=>危険変更されないされません。第二の方法の

短所:

非常に詳細な、非常に読みにくく...もちろん

は、あなたはこの1のような単純なコードのために、第一の方法は本当に便利であることを私に言うだろう。

しかし、コンセプト/コードの難しさを考慮しなければ、私は読者(初心者でもない)にとってもより論理的で明白な第2の方法を敬遠します。

しかし、戻り値の型を持ち、副作用のない副作用や潜在的な副作用を伴うvoid戻り値を持つ "command"メソッドを考慮したCQSの原則に違反します。

だから、動機づけプログラマーはどのように採用すべきですか?コードケースに合わせた2つのミックス?または、「法律」を常にイン・アウト・パラメーターを避けることを期待してください。

(もちろん、要素を追加する方法は例を説明するための名前であり、実際のコードでは悪い選択です)。

答えて

5

私は法律があるべきだと思う:広範囲に常に文書あなたのメソッドの動作をよりストレートフォワードですが、常に

使用。メソッドの名前はaddElementsToExistingListですが、既存のリストに要素を追加しない方法 - それは新しいものを作成します。

あなたの第二の例では、保証のバグを持っているでしょうドキュメンテーションなしで非常に素晴らしいケースです。対話型で直感的で誤解を招くような名前です...

+0

私はあなたに非常に同意しますが、それはいくつかの(実験されていない常に)行う方法の最も一般的なスタイルを表しています:)実際、私は働いている場所で悪い名前で、 – Mik378

0

あなたの例の場合、名前がわかります - "addElementsToExistingList"は私にはかなり明確に思われます.. ええと。しかし、あなたの懸念はあまり明確な名前で正当化されるでしょう。

は、例えば、ルビーでこれは一般的に

+1

少し詳細を除いて:既存のリストは変更されていないので、*ヒント*は2番目のスニペットで完全に間違っています:-) – thkala

0

それはにファイン可変元だ命名規則

"a".upcase =>あなたの変数の大文字を与え、葉オリジナルそのまま "a".upcase! =>が変更されて処理されます文書化されている限り、パラメータを変更/変更してください。もちろん、メソッド名が "addElementsToExistingList"の場合、他に何を期待するべきですか?しかし、以前に指摘したように、2番目の実装ではコピーが返され、元のものは変更されないため、メソッド名が誤解を招くようになりました。あなたの最初の方法は、物事を行うための完全に受け入れられる方法です。その他の追加的な改善点は、すべての要素だけがリストに追加された場合にtrueを示すtrue/false値を戻り値に追加することです。

2

3つ目の方法があります。それはList実装プライベートを保つので、私はこのアプローチが好き

class ElementList { 
    private List<String> = new ArrayList<String>(); 

    public void addElements(Element... elements); 
} 

:自分自身に要素を追加する方法を知っているクラスにList<String>を包みます。あなたのメソッドに不変のリストを渡すか、パラメータが変更されるかどうかは心配する必要はありません。コードは簡単です。 addElementsToExistingListのような長いメソッド名は、オブジェクトが別のオブジェクトがやっていなければならないことをしようとするコードの匂いです。

2

パラメータであるオブジェクトに変更を加えるときには常に文書化してください。そうしないと、呼び出し元に意図しない副作用が生じる可能性があります。最初のケースでは、メソッド名が十分な文書であるとコメントした他の人に同意します。

2番目の例では、すでにmyListに存在する要素が2回追加されているようです。要素が一度だけ追加されるため、このコードは、2番目の例と同等ではありませんが、私は、これは実際には何だと思うことに注意を

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()); 

:実際には、あなたは完全にaddElementsToExistingListメソッドのパラメータを削除することもできますし、としてそれを書き換えますあなたは意図した。これは私が通常好むスタイルです。このコードは、余分なコードを追加しないと、最初の例よりも理解しやすく柔軟になります(パフォーマンスはごくわずかに低下することがありますが、これは通常問題ではありません)。 getElements()のクライアントは、既存のコレクションに追加するだけでなく、要素リストを使って他のこともできるようになりました。