Tbpgr Blog

Employee Experience Engineer tbpgr(てぃーびー) のブログ

書籍 リファクタリング−プログラマーの体質改善 | データの再編成 | State/Strategyによるタイプコードの置き換え

パンくず

リファクタリング-プログラマーの体質改善テクニック
データの再編成
State/Strategyによるタイプコードの置き換え

内容

リファクタリング

State/Strategyによるタイプコードの置き換え

適用ケース要約

クラスのふるまいに影響を与えるタイプコードが使われており、タイプコードは実行時に変更される。

適用内容要約

タイプコードをState/Strategyオブジェクトに取り換える

適用詳細

基本的には「クラスによるタイプコードの置き換え」、「サブクラスによるタイプコードの置き換え」と同じ考えだが、
置き換える対象のタイプコードが実行時に変化する場合はこちらのリファクタリングを適用する。
状態を扱うならState、アルゴリズムを扱うならStrategyを使用します。

サンプル

時刻によって値段が変わる定食屋さんを実装します
12時台、13時台はランチ料金で2割引き。
22時から24時は深夜料金で2割増し。
その他は通常料金とします。

サンプルコード

リファクタリング

# encoding: Shift_JIS

class Diner
  LUNCH_TIME_PRICE_RATE = 0.8
  NIGHT_TIME_PRICE_RATE = 1.2
  DEFAULT_PRICE_RATE = 1

  def get_price(base_price)
    rate=DEFAULT_PRICE_RATE
    case Time.new.hour
    when 12..13
      rate=LUNCH_TIME_PRICE_RATE
    when 22..24
      rate=NIGHT_TIME_PRICE_RATE
    else
    end
    return base_price*rate
  end
end

diner = Diner.new
base_price=1000
puts diner.get_price(base_price)

リファクタリング

# encoding: Shift_JIS

class Diner
  def get_price(base_price)
    return DinerPriceCalculator.get_instance.calculate_price(base_price)
  end
end

class DinerPriceCalculator
  DEFAULT_PRICE_RATE = 1.0
  def self.get_instance()
    case Time.new.hour
    when 12..13
      return LunchDinerPriceCalculator.new
    when 22..24
      return NightDinerPriceCalculator.new
    else
      return self.allocate
    end
  end
  
  def get_rate()
    return  DEFAULT_PRICE_RATE
  end
  
  def calculate_price(base_price)
    base_price*get_rate()
  end
end

class LunchDinerPriceCalculator < DinerPriceCalculator
  LUNCH_TIME_PRICE_RATE = 0.8
  def get_rate()
    return LUNCH_TIME_PRICE_RATE
  end
end

class NightDinerPriceCalculator < DinerPriceCalculator
  NIGHT_TIME_PRICE_RATE = 1.2
  def get_rate()
    return NIGHT_TIME_PRICE_RATE
  end
end

diner = Diner.new
base_price=1000
puts diner.get_price(base_price)

出力(共通)
12時から13時台に実行した場合

800.0

22時から24時台に実行した場合

1200.0

その他の時間に実行した場合

1000.0

補足

今回はサンプルなので定数を返す部分しか差異がありませんが、
このような場合は基底クラスに一本化するのが好ましいです。
※次のリファクタリング手法である
「フィールドによるサブクラスの置き換え」
の適用対象にあたります