web-dev-qa-db-ja.com

フィールド、コンストラクター、または引数で初期化する

フィールドの初期化先がわかっている場合、フィールド、コンストラクターで初期化するか、パラメーターとして受け取る必要がありますか?ベストプラクティスについて質問しています。 3つのオプションはすべて、実質的に同じ結果を提供します。私はそれが取るに​​足りないと思うので、裏で起こっていることを考慮していません。

これは好奇心のための一般的な質問です。過去にはありましたが、現時点では特に問題はありません。次の例では、ArrayListを使用します。これは、初期化する内容がわかっている場合であり、実際に別の既存のArrayListに初期化したい場合でも、事前初期化しても問題はありません。またはありますか?

たとえば、ArrayListはどこで初期化する必要がありますか?

フィールドで初期化:

import Java.util.ArrayList;

public class Initializer {
    private ArrayList<String> arrayList = new ArrayList<String>();

    public void addString(String string) {
        arrayList.add(string);
    }
}

コンストラクターで初期化:

import Java.util.ArrayList;

public class Initializer {
    private ArrayList<String> arrayList;

    public Initializer() {
        arrayList = new ArrayList<String>();
    }

    public void addString(String string) {
        arrayList.add(string);
    }
}

パラメータとして初期化:

import Java.util.ArrayList;

public class Initializer {
    private ArrayList<String> arrayList;

    public Initializer(ArrayList arrayList) {
        this.arrayList = arrayList;
    }

    public void addString(String string) {
        arrayList.add(string);
    }
}
2
Evorlor

パラメータとして初期化するとカプセル化が解除され、呼び出し側は渡されたリストを使用して必要な処理を実行できます(奇数時にクリアされます)。

ArrayList<String> list = new ArrayList<String>();
Initializer init = new Initializer(list);
//do various thing
list.clear();
//now the list in init is also empty while init may still expect it to be filled

他の2つのオプションの場合、初期化する内容によって異なります。

たとえば、スレッドセーフキューを必要とするクラスは、いくつかの実装(リンクリスト、循環バッファーなど)のいずれかを使用できます。コンストラクターは、パラメーターに基づいて使用するか、呼び出されたコンストラクターを決定し、パラメーターをコンストラクターに渡すことさえできます。オブジェクトの。

public Initializer(boolean useLinked) {
    if(useLinked){
        this.arrayList = new LinkedList<String>();
    else 
        this.arrayList = new ArrayList<String>();
}

実装が常に同じ場合は、フィールドまたは初期化ブロックで初期化し、それを最終としてマークします。

public class Initializer {
    private final ArrayList<String> arrayList = new ArrayList<String>();
}

これにより、他のメソッドが誤って上書きするのを防ぎます。

7
ratchet freak

フィールドの初期化先がわかっている場合

あなたがそれを知っているなら、あなたのクラスが非常に再利用可能ではないか、またはあなたがあなたのクラスが現在そして将来どのように使われるかを知っていると思い込んでいる可能性が非常に高いです-実際にいくつかの可能なユースケースを見逃している間。クラスが意味的に何をするべきかについてより多くの情報を提供するなら、私はこれをより詳細に説明することができます。

通常は、パラメーターによる初期化を使用するのが最適です(前述のように、引数が変更され、常に空のリストであるとは限りません)。このデザインは_depedency injection_とも呼ばれます。それはいくつかの利点があります。例えば。それらの1つは、はるかに優れたテスト容易性です。

具象型のみを受け入れる代わりに、インターフェースも使用する必要があります。だからあなたは行くべきです:

_//(...)
private List<String> someList ;

    public Initializer(List someList ) {
        this.someList = someList ;
    }
_

そして、誰かがnew Initializer(new ArrayList()) ORによって新しい初期化子を作成することができます。これはnew Initializer(new CopyOnWriteArrayList())のようなことをすることができます。クラスのユーザーは、どの種類のリストを使用するかを最適に決定できます。クラス作成者は、それがArrayListであるかCopyOnWriteArrayListであるかを気にしませんか?List -同じ方法でアイテムを追加できるもの。

0
valenterry