ケアレスミスを無くす章

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

『目的』

複数のコンストラクタを作るときの一工夫で修正忘れを減らしましょう。

『Before』

コンストラクタは引数の型や引数の数を変更することで1クラス内に複数宣言することができますよね。

/**
 * 文字を持たず、初期容量が 16 文字である文字列バッファを構築します。
 */
public StringBuffer() {
    value = new char[16];
}

/**
 * 文字を持たず、引数 length によって指定された初期容量である
 * 文字列バッファを構築します。
 * 
 * @param   length 初期容量
 * @throws  NegativeArraySizeException 引数 length が0未満の場合
 */
public StringBuffer(int length) {
    value = new char[length];
}

/**
 * 文字列バッファを構築し、文字列引数に等しい文字列を表すようにします。
 * つまり、文字列バッファの初期内容は引数文字列のコピーになります。
 * 文字列バッファの初期容量は、16 と文字列引数の長さを加えたものになります。
 * 
 * @param   str バッファの初期内容
 */
public StringBuffer(String str) {
    value = new char[str.length() + 16];
    append(str);
}

複数のコンストラクタを作るとき、それぞれに初期化内容を書いてしまうと面倒なことになります。 後で初期化内容に変更が加わった場合に修正箇所が多いし、修正漏れの危険性も潜んでいます。

『After』

上記例のStringBufferクラスは3種類のコンストラクタを持っています。 やりたいことはそれぞれ以下です。

  StringBuffer() 
    初期容量が 16 文字である文字列バッファを構築する。
  StringBuffer(int length) 
    引数 length によって指定された初期容量である文字列バッファを構築する。 
  StringBuffer(String str) 
    文字列バッファを構築して文字列引数に等しい文字列を表すようにする。

ということは、文字列バッファを構築することは共通ですよね。
書き替えてみましょう。
/**
 * 文字を持たず、初期容量が 16 文字である文字列バッファを構築します。
 */
public StringBuffer() {
    this(16);
}

/**
 * 文字を持たず、引数 length によって指定された初期容量である
 * 文字列バッファを構築します。
 * 
 * @param   length 初期容量
 * @throws  NegativeArraySizeException 引数 length が0未満の場合
 */
public StringBuffer(int length) {
    value = new char[length];
}

/**
 * 文字列バッファを構築し、文字列引数に等しい文字列を表すようにします。
 * つまり、文字列バッファの初期内容は引数文字列のコピーになります。
 * 文字列バッファの初期容量は、16 と文字列引数の長さを加えたものになります。
 * 
 * @param   str バッファの初期内容
 */
public StringBuffer(String str) {
    this(str.length() + 16);
    append(str);
}

どのコンストラクタを呼んでも、this を使って『StringBuffer(int length)』を経由しています。
このコンストラクタが “catch-all” コンストラクタの役割を担っています。

コンストラクタを修正する場合、『StringBuffer(int length)』を修正すれば修正忘れは減りますね。

『まとめ』

より多くのパラメータを受ける “catch-all” コンストラクタを用意してデフォルト値を提供するようにしましょう。 今回の例はパラメータが少ないのであまり効果はないのですが、もっとパラメータが多ければありがたみがわかるかもしれません。

< 前のページへ

Pagetop