web-dev-qa-db-ja.com

Javaでのコンストラクタのオーバーロード-ベストプラクティス

これに似たトピックがいくつかありますが、十分な答えのあるトピックは見つかりませんでした。

Javaでのコンストラクタのオーバーロードのベストプラクティスを知りたいと思います。私はすでにこのテーマについて自分の考えを持っていますが、もっとアドバイスを聞きたいです。

単純なクラスでのコンストラクターのオーバーロードと、既にオーバーロードされたクラスの継承中のコンストラクターのオーバーロードの両方を参照しています(つまり、基本クラスにはコンストラクターがオーバーロードされています)。

ありがとう:)

104
Eyal Roth

「公式ガイドライン」はありませんが、KISSおよびDRYの原則に従います。オーバーロードされたコンストラクターをできるだけシンプルにします。最も簡単な方法は、this(...)のみを呼び出すことです。そうすれば、パラメーターを一度だけ確認して処理するだけで済みます。

public class Simple {

    public Simple() {
        this(null);
    }

    public Simple(Resource r) {
        this(r, null);
    }

    public Simple(Resource r1, Resource r2) {
        // Guard statements, initialize resources or throw exceptions if
        // the resources are wrong
        if (r1 == null) {
            r1 = new Resource();
        }
        if (r2 == null) {
            r2 = new Resource();
        }

        // do whatever with resources
    }

}

単体テストの観点からは、リソースをクラスに入れることができるため、クラスのテストが簡単になります。クラスに多くのリソースがある(または一部のOOオタクがそれを呼ぶように協力者)場合は、次の2つのことのいずれかを検討してください。

パラメータクラスを作成する

public class SimpleParams {
    Resource r1;
    Resource r2;
    // Imagine there are setters and getters here but I'm too lazy 
    // to write it out. you can make it the parameter class 
    // "immutable" if you don't have setters and only set the 
    // resources through the SimpleParams constructor
}

Simpleのコンストラクターは、SimpleParamsパラメーターのみを分割する必要があります。

public Simple(SimpleParams params) {
    this(params.getR1(), params.getR2());
}

…またはSimpleParamsを属性にします。

public Simple(Resource r1, Resource r2) {
    this(new SimpleParams(r1, r2));
}

public Simple(SimpleParams params) {
    this.params = params;
}

ファクトリークラスを作成する

リソースを初期化するファクトリクラスを作成します。これは、リソースの初期化が少し難しい場合に便利です。

public interface ResourceFactory {
    public Resource createR1();
    public Resource createR2();
}

その後、コンストラクターは、パラメータークラスと同じ方法で実行されます。

public Simple(ResourceFactory factory) {
    this(factory.createR1(), factory.createR2());
} 

両方を組み合わせて

ええ...あなたがその時にあなたにとってより簡単なものに応じて、両方の方法を組み合わせてマッチさせることができます。パラメータクラスと単純なファクトリクラスは、同じ方法で使用されるSimpleクラスを考慮すると、ほとんど同じものです。

164
Spoike

ベストプラクティスは、関連パラメータのデフォルトでthis()を呼び出すことでオーバーロードされたコンストラクターが参照する単一のプライマリコンストラクターを持つことだと思います。この理由は、オブジェクトの構築された状態が何であるかをより明確にするためです-実際には、プライマリコンストラクターを実際のコンストラクターのみ、他のコンストラクターはそれに委任するだけです

この一例はJTableかもしれません-プライマリコンストラクターはTableModel(および列と選択モデル)を取り、他のコンストラクターはこのプライマリコンストラクターを呼び出します。

スーパークラスに既にオーバーロードされたコンストラクターがあるサブクラスの場合、親クラスのコンストラクターをprimaryそして、単一のプライマリコンストラクタを持たないことは完全に合法だと思います。たとえば、Exceptionを拡張するとき、3つのコンストラクターを提供することがよくあります。1つはStringメッセージを受け取り、1つはThrowableの原因を取り、もう1つは両方を受け取ります。これらの各コンストラクターは、superを直接呼び出します。

73
oxbow_lakes

いくつかの組み合わせのみが有効な多くのオプションを持つ非常に複雑なクラスがある場合は、Builderの使用を検討してください。コード的にも論理的にも非常にうまく機能します。

Builderは、フィールドを設定するためだけに設計されたメソッドを持つネストされたクラスであり、ComplexClassコンストラクターは引数としてそのようなBuilderのみを取ります。


編集:ComplexClassコンストラクターは、Builderの状態が有効であることを確認できます。 ComplexClassでセッターを使用するだけの場合、これは非常に困難です。

すべてのクラスが同じように作成されるわけではないため、クラスの種類に本当に依存します。

一般的なガイドラインとして、2つのオプションを提案します。

  • value&immutableクラス(例外、整数、DTOなど)の場合は、上記の回答で示唆されているように単一のプライマリコンストラクターを使用します
  • 他のすべて(セッションBean、サービス、可変オブジェクト、JPAおよびJAXBエンティティなど)には、デフォルトコンストラクターのみを使用し、追加の構成なしで使用できるようにすべてのプロパティに適切なデフォルトを設定
2

さて、ここにオーバーロードされたコンストラクタの例を示します。

public class Employee
{
   private String name;
   private int age;

   public Employee()
   {
      System.out.println("We are inside Employee() constructor");
   }

   public Employee(String name)
   {
      System.out.println("We are inside Employee(String name) constructor");
      this.name = name;
   }

   public Employee(String name, int age)
   {
      System.out.println("We are inside Employee(String name, int age) constructor");
      this.name = name;
      this.age = age;
   }

   public Employee(int age)
   {
      System.out.println("We are inside Employee(int age) constructor");
      this.age = age; 
   }

   public String getName()
   {
      return name;
   }

   public void setName(String name)
   {
      this.name = name;
   }

   public int getAge()
   {
      return age;
   }

   public void setAge(int age)
   {
      this.age = age;
   }
}

上記の例では、オーバーロードされたコンストラクターを見ることができます。コンストラクターの名前は同じですが、各コンストラクターには異なるパラメーターがあります。

Javaでのコンストラクタのオーバーロードにさらに光を当てるリソースをいくつか紹介します。

コンストラクター

コンストラクターの説明

0
Shiva