Home > IT > Java言語で学ぶリファクタリング入門 #8

Java言語で学ぶリファクタリング入門 #8

  • 2008-12-22 (Mon)
  • IT

今日はディシディアとは温度差のあるリファクタリングネタで。

第 8 章。

Java言語で学ぶリファクタリング入門

サブクラスによるタイプコードの置き換え

前回の続きで、switch 文を消しにかかります。

 public static ShunmiFactor getShunmiFactorFrom(Mysidian mysidian){
  switch (mysidian.getType()) {
  case TYPE_WARLOCKREPORT:
   //execute WarlockReport process
  case TYPE_DIEL:
   //execute Diel process
  case TYPE_ELIO:
   //execute Elio process
  }
  ...
 }

オブジェクト指向では、条件判断とその後の処理はクラスを分けることで実装することができます。
Java では同一クラスの継承(extends)、同一インターフェースの実装(implements)などで、これを実現します。
いわゆるポリモーフィズム(多様性)というヤツですが、今回は同一クラスの継承でいってみます。

その前に・・・。

もし、前職関係者でこのエントリーを読んでいる方がいたら、例は次のように置き換えて読んで下さい。

 ■Mysidian > 預金
 □WarlockReport > 普通預金
 □Diel > 定期預金
 □Elio > 外貨預金

「そんな分岐しねーよ」という意見もあるかもしれませんが、入口の方でやってませんか?
もう少し範囲を狭めて

 ■Mysidian > 定期預金
 □WarlockReport > 商品 A
 □Diel > 商品 B
 □Elio > 商品 C

こういう風に解釈してもよいかもしれません。
そして、思い出してみて下さい。
取引や商品が増えるたびに IF 文をあちこちに書いて大変な目にあった経験はありませんか?

と、前置きはここまでにして。

例では Mysidian によって処理分岐をしているので、まず Mysidian というクラスを作ります。

 public abstract class Mysidian {
  public abstract ShunmiFactor getShunmiFactor();
 }

前回は enum でしたが、今回は抽象クラスになります。
また、抽象メソッドとして getShunmiFactor を宣言しておきます。
この Mysidian を継承して、WarlockReport、Diel、Elio の各クラスを作ります。
とりあえず、WarlockReport を。

 public class WarlockReport extends Mysidian{
  @Override
  public ShunmiFactor getShunmiFactor() {
   //execute WarlockReport process
   ...
  }
 }

Mysidian の抽象メソッド getShunmiFactor を実装して、WarlockReport の処理を書きます。
Diel、Elio にもそれぞれの処理を書きます。
これで switch 文の case 内に書かれていた処理が、各クラスに移ったことになります。

しかし、このパターンの弱点は「クラスが増える」という点です。
あまりにクラスが多すぎると管理が煩雑になるのですが、美しくクラス設計ができた場合、クラスの違いは仕様の違いを表すことになります。
それは、オブジェクト指向プログラミングで現実世界の「もの」を表現する・・・の真の意味です、たしか、たぶん。
また、このパターンでは、分岐が増えた場合、switch 文の case を追加するのではなく、新たなクラスを追加することになります。
つまり、拡張時に既存のコードを書き換えなくても良いので、デグレの抑制にもつながります。
・・・長所と短所は表裏一体、ままならぬものよ。

そして MysidiaUtil を書き直すと、

 public class MysidiaUtil {
  public static ShunmiFactor getShunmiFactorFrom(Mysidian mysidian){
   return mysidian.getShunmiFactor();
  }
 }

こうなるのですが、これならそもそも MysidiaUtil.getShunmiFactorFrom は必要なく、呼び出し側で、

 Mysidian mysidian = new WarlockReport();
 ShunmiFactor factor = mysidian.getShunmiFactor();

と書いてあげれば良いですね。
そして、リファクタリング前後(上下)のクラス図チックなものがこれ。

081222.PNG

リファクタリング前はパラメータ(Mysidian)を渡すと結果(ShunmiFactor)を返す関数のような実装。
リファクタリング後は各 Mysidian をオブジェクト(いわゆるデータと処理の固まり)として実装したイメージになります。

残る問題は Mysidian の(サブクラスの)インスタンス生成です。
switch 文で case 分岐するように、上の例で new されている WarlockReport はパラメータ(1 or 2 or 3)によって、Diel であったり Elio であったりするはずです。

そこは Factory Method で・・・ということで、次回に続きます。

Home > IT > Java言語で学ぶリファクタリング入門 #8

Page Top