Tbpgr Blog

元エンジニア 人事 tbpgr(てぃーびー) のブログ

実装パターン | メソッド

概要

メソッドについて
(この書籍のベースはJavaの話)

詳細

複合メソッド

他のメソッドを呼び出すコードでメソッドを構成する。
各呼び出しは処理の粒度を揃える。
メソッド分割のオーバーヘッドは可読性に比べたら大したものではない。

意図を示す名前

利用目的に即した命名を行うこと。
処理の詳細を伝えるような命名よりも目的のみを伝える方がよい。

メソッドの可視性

Javaはpublic,パッケージ,protected,privateの可視性がある。
公開範囲が広いほど以降の変更に対する製薬が厳しくなる。
公開範囲は可能な限り狭くすることが望ましい。

メソッドオブジェクト

複雑な長い処理がある場合はその一部をオブジェクトとして独立させる。
例えば下記のような国民総生産を計算する長い処理があったとします。

void calclateGnp() {
  GDPの計算開始
  : ※長い処理
  GDPの計算終了

  海外からの所得計算開始
  : ※長い処理
  海外からの所得計算終了

  海外への所得支払い計算開始
  : ※長い処理
  海外への所得支払い計算終了

  GDP-(海外からの所得-海外への所得支払い)
}

以下のように分割します。

void calclateGnp() {
  GdpCalclator gdpCalclator = new GdpCalclator();
  gdp = gdpCalclator.calclate();

  ForeignIncomeCalclator foreignIncomeCalclator = new ForeignIncomeCalclator();
  foreignIncome = foreignIncomeCalclator.calclate();
  
  ForeignOutputCalclator foreignOutputCalclator = new ForeignOutputCalclator();
  foreignOutputCalclator = foreignOutputCalclator.calclate();

  return gdp-(foreignIncome - foreignOutputCalclator)
}
オーバーライドメソッド

スーパークラスの抽象メソッドはオーバーライドを示唆する。
スーパークラスの複合メソッドはサブクラスでオーバーライドすることを容易にする。
スーパークラスメソッド粒度が荒く、長い処理が多いとサブクラス側で柔軟に対応できなくなる。

オーバーロードメソッド

同じメソッドを異なる引数で対応させる場合に利用。同じ目的の処理に対して利用する。
目的が異なる場合はメソッド名を別の名前にする。

メソッドが返す型

副作用の有無を戻りの型で表す。副作用がある場合は戻りをvoidとする。
副作用がなければ任意の型を戻す。
戻り値の型は出来るだけ抽象的な型を返却することで柔軟性を保つ。

メソッドのコメント

メソッドのコメントはどうしてもコードだけでは伝えられない内容のみに限定する。
基本は命名と構造で内容が伝わるように留意する。
それテャ別にJavadocなどのドキュメンテーションコメントを書くのは良い。
テストクラスがコメントの役割を果たす場合もある。

ヘルパーメソッド

複合メソッドの結果として作成される小さなメソッド
外部メソッドとして抽出したり、スーパークラスの処理にしたりと次のリファクタリングの元となることも多い。

デバッグ出力メソッド

toStringは可能な限り実装して、デバッグやログ出力時に有力な情報を出力するのを容易にしておくこと。
toStringを実装せずに毎回各フィールドにアクセスしようとすると思いの外手間がかかるものだ。

変換

変換処理が必要な場合、コピー・変換後のインターフェースへの変換、和集合へのマージなど様々なバリエーションがある。

変換メソッド

似たような型を持つオブジェクト間なら変換元、変換元のどちらかに変換メソッドを作成する。
変換元に変換メソッドを用意する場合は、一部のクラスに変換処理が大量に出来てしまったり組み込みクラスにはそもそもメソッド追加出来なかったり
など問題点も多い。
Hogeフォーマットというフォーマットがあるとして・・・

Hoge#asYaml
Hoge#asCsv
Hoge#asLtsv

などのようにする。

変換コンストラクタ

変換元のオブジェクトを引数にとり、変換後のオブジェクトを返却する。

生成

オブジェクトの生成には明確な表現と柔軟性が求められる。

完全なコンストラクタ

オブジェクト生成後の操作で必至となる項目はすべてコンストラクタで提供する。
コンストラクタの引数がユーザーに利用のための条件を伝えることとなる。
コンストラクタの引数がオプション要素の場合はコンストラクタオーバーロードして内部でチェーンする。

ファクトリメソッド

利点として、柔軟性が増す。
コンストラクタは自分の型しか返却出来ないが、子クラスの型などを返却可能になる。

内部ファクトリ

複雑になった生成処理を隠蔽して柔軟に変更可能にする。

コレクション用アクセサメソッド

コレクションに対するアクセサを用意した場合、データを壊される可能性がある。
必要に応じて一部のアクセサのみを用意する。
例えば、add,remove,iterateなど。

論理値設定メソッド

真偽値を持つフィールドがある場合、通常のセッターよりも
true・falseそれぞれの意味を持ったsetterを用意するほうが良い。

class Hoge {
  private boolean isBlackCompany;

  public void setWhiteCompany() {
    this.isBlackCompany = false;
  }
  public void setBlackCompany() {
    this.isBlackCompany = true;
  }
}
クエリーメソッド

処理の判断のために必要なオブジェクトの状態を返却して
他のオブジェクトの意思決定をサポートする。

等価性メソッド

equals,hashCodeを実装する。

getterメソッド

オブジェクトの状態へのアクセス窓口。
抽象化・隠蔽することで容易に中身の処理を変更可能。

setterメソッド

getter同様。ただし、setterは性質上データの更新・設定に関わる可能性が高いためより重要度が高い。

安全なコピー

参照元に影響を与えないようにコピーを利用する。