凪瀬 Blog
Programming SHOT BAR

目次

Blog 利用状況
  • 投稿数 - 260
  • 記事 - 0
  • コメント - 46610
  • トラックバック - 192
ニュース
広告
  • Java開発者募集中
  • 経歴不問
  • 腕に自信のある方
  • 富山市内
  • (株)凪瀬アーキテクツ
アクセサリ
  • あわせて読みたい
凪瀬悠輝(なぎせ ゆうき)
  • Java技術者
  • お茶好き。カクテル好き。
  • 所属は(株)凪瀬アーキテクツ
  • Twitter:@nagise

書庫

日記カテゴリ

 

Kanazawa.processではテスト駆動開発入門を読んで、テスト駆動開発を学びました。その本でのテスト駆動開発のサンプルとして挙がっていたテーマは複数通貨のMoneyを作るというものでした。

Dollarという米ドルを表現するオブジェクトを作り、Francというスイス・フランを表すオブジェクトを作り、そしてMoneyというオブジェクトに統合していくというリファクタリングの過程を経ています。

これをジェネリクスを使って設計したらどうなるでしょうか。

public abstract class Money<T extends Money<T>> {
  public abstract T add(Money<?> m);
}

Moneyオブジェクトに演算用のメソッドadd()を定義します。引き算や掛け算など要求に合わせて各種用意するといいでしょう。

Money<T extends Money<T>> という型変数の宣言方法は自己言及するジェネリクスの稿で 取り上げた手法です。add()の戻り型をTとしておくことで具象型自身の型を返させることができます。

これをDollarやFrancでオーバーライドして実装します。

public class Dollar extends Money<Dollar> {
  @Override
  public Dollar add(Money<?> m) {
    // ...
  }
}

こうすることで、Dollarのadd()はDollar型で返るわけです。 しかし、これだけだとDollarやFrancといった通貨単位ごとにadd()の実装を施さねばなりません。 protectedなファクトリーメソッドを用意して、オブジェクトの生成を具象型に委譲することで スーパークラスであるMoney型で統一的にadd()を記述することができます。

public abstract class Money<T extends Money<T>> {
  /** 為替レート */
  Map<Class<? extends Money<?>>, Map<Class<? extends Money<?>>, Double>> rateMap;
  /** 値 */
  protected double value;
  /** 加算メソッドの共通実装 */
  public T add(Money<?> m) {
    double rate = rateMap.get(this.getClass()).get(m.getClass());
    return getInstance(this.value + m.value * rate);
  }
  /** 具象型の生成 */
  protected abstract T getInstance(double value);
  /** コンストラクタ */
  protected Money(double value) {
    this.value = value;
  }
}

こうした手法で通貨単位ごとに型を作って何が嬉しいかと言えば、ドル建てである場所にスイス・フランの型が紛れ込んだ場合に コンパイルエラーにすることができるという点です。

設計にはいろんな手法がありますし、それぞれにメリット、デメリットがあるので要求に合わせて柔軟に選べるようにしたいものですね。

投稿日時 : 2009年5月19日 0:54
コメント
No comments posted yet.
タイトル
名前
Url
コメント