Javaにおけるコンストラクタの手引き

Javaのコンストラクターのガイド

1. 前書き

コンストラクターはobject-oriented designのゲートキーパーです。

このチュートリアルでは、作成中のオブジェクトのthe internal stateを初期化する単一の場所としてそれらがどのように機能するかを確認します。

先に進んで、銀行口座を表す単純なオブジェクトを作成しましょう。

2. 銀行口座の設定

銀行口座を表すクラスを作成する必要があると想像してください。 名前、作成日、残高が含まれます。

また、toStringメソッドをオーバーライドして、詳細をコンソールに出力しましょう。

class BankAccount {
    String name;
    LocalDateTime opened;
    double balance;

    @Override
    public String toString() {
        return String.format("%s, %s, %f",
          this.name, this.opened.toString(), this.balance);
    }
}

現在、このクラスには、銀行口座に関する情報を格納するために必要なすべてのフィールドが含まれていますが、コンストラクターはまだ含まれていません。

これは、新しいオブジェクトを作成した場合、フィールド値が初期化されないことを意味します。

BankAccount account = new BankAccount();
account.toString();

上記のtoString メソッドを実行すると、オブジェクトnameopenedがまだnullであるため、例外が発生します。

java.lang.NullPointerException
    at com.example.constructors.BankAccount.toString(BankAccount.java:12)
    at com.example.constructors.ConstructorUnitTest
      .givenNoExplicitContructor_whenUsed_thenFails(ConstructorUnitTest.java:23)

3. 引数なしのコンストラクタ

コンストラクターでそれを修正しましょう:

class BankAccount {
    public BankAccount() {
        this.name = "";
        this.opened = LocalDateTime.now();
        this.balance = 0.0d;
    }
}

作成したコンストラクタに関するいくつかのことに注意してください。 まず、これはメソッドですが、戻り値の型はありません。 これは、コンストラクターが作成するオブジェクトのタイプを暗黙的に返すためです。  new BankAccount()を呼び出すと、上記のコンストラクターが呼び出されます。

第二に、引数を取りません。 この特定の種類のコンストラクターは、no-argument constructorと呼ばれます。

しかし、なぜ初めてそれが必要でなかったのですか? don’t explicitly write any constructor, the compiler adds a default, no-argument constructorのときです。

これが、コンストラクターを明示的に記述していなくても、オブジェクトを初めて構築できた理由です。 デフォルトの引数なしのコンストラクターは、すべてのメンバーを単にdefault valuesに設定します。

オブジェクトの場合、それはnull,であり、前に見た例外が発生しました。

4. パラメータ化されたコンストラクタ

コンストラクターの本当の利点は、オブジェクトに状態を挿入するときにencapsulationを維持するのに役立つことです。

したがって、この銀行口座で本当に便利なことをするには、オブジェクトに初期値を実際に注入できる必要があります。

これを行うには、let’s write a parameterized constructor, that is, a constructor that takes some arguments

class BankAccount {
    public BankAccount() { ... }
    public BankAccount(String name, LocalDateTime opened, double balance) {
        this.name = name;
        this.opened = opened;
        this.balance = balance;
    }
}

これで、BankAccountクラスで何か便利なことができます。

    LocalDateTime opened = LocalDateTime.of(2018, Month.JUNE, 29, 06, 30, 00);
    BankAccount account = new BankAccount("Tom", opened, 1000.0f);
    account.toString();

このクラスには2つのコンストラクターがあります。 明示的な引数なしのコンストラクターとパラメーター化されたコンストラクター。

コンストラクタは好きなだけ作成できますが、作成しすぎないようにしたいでしょう。 これは少し混乱するでしょう。

コード内のコンストラクターが多すぎる場合は、いくつかのCreational Design Patternsが役立つ場合があります。

5. コピーコンストラクター

コンストラクターは、初期化のみに限定される必要はありません。 また、ビヘイビアの作成にも使用できます。 Imagine that we need to be able to create a new account from an existing one.

新しいアカウントは、古いアカウントと同じ名前で、今日の作成日であり、資金はありません。 We can do that using a copy constructor:

public BankAccount(BankAccount other) {
    this.name = other.name;
    this.opened = LocalDateTime.now();
    this.balance = 0.0f;
}

現在、次の動作があります。

LocalDateTime opened = LocalDateTime.of(2018, Month.JUNE, 29, 06, 30, 00);
BankAccount account = new BankAccount("Tim", opened, 1000.0f);
BankAccount newAccount = new BankAccount(account);

assertThat(account.getName()).isEqualTo(newAccount.getName());
assertThat(account.getOpened()).isNotEqualTo(newAccount.getOpened());
assertThat(newAccount.getBalance()).isEqualTo(0.0f);

6. チェーンコンストラクター

もちろん、コンストラクターパラメーターまたはgive some of them default values.の一部を推測できる場合があります。

たとえば、名前だけで新しい銀行口座を作成できます。

それでは、nameパラメーターを使用してコンストラクターを作成し、他のパラメーターにデフォルト値を指定しましょう。

public BankAccount(String name, LocalDateTime opened, double balance) {
    this.name = name;
    this.opened = opened;
    this.balance = balance;
}
public BankAccount(String name) {
    this(name, LocalDateTime.now(), 0.0f);
}

キーワードthis,を使用して、他のコンストラクターを呼び出しています。

if we want to chain a superclass constructor we have to use super instead of this.を覚えておく必要があります

また、this or super expression should always be the first statement.

7. 値タイプ

Javaでのコンストラクターの興味深い使用法は、Value Objectsの作成です。 A value object is an object that does not change its internal state after initialization.

That is, the object is immutable。 Javaの不変性は少しnuancedであり、オブジェクトを作成するときは注意が必要です。

先に進んで、不変のクラスを作成しましょう。

class Transaction {
    final BankAccount bankAccount;
    final LocalDateTime date;
    final double amount;

    public Transaction(BankAccount account, LocalDateTime date, double amount) {
        this.bankAccount = account;
        this.date = date;
        this.amount = amount;
    }
}

クラスのメンバーを定義するときにfinalキーワードを使用することに注意してください。 つまり、これらの各メンバーは、クラスのコンストラクター内でのみ初期化できます。 後で他のメソッド内で再割り当てすることはできません。 これらの値を読み取ることはできますが、変更することはできません。

If we create multiple constructors for the Transaction class, each constructor will need to initialize every final variable.そうしないと、コンパイルエラーが発生します。

8. 結論

コンストラクターがオブジェクトを作成するさまざまな方法について説明しました。 慎重に使用すると、構造体はJavaのオブジェクト指向設計の基本的な構成要素を形成します。

いつものように、コードサンプルはover on GitHub.で見つけることができます