読者です 読者をやめる 読者になる 読者になる

Tbpgr Blog

Ruby プログラマ tbpgr(てぃーびー) のブログ

Ruby | Collecting Inputs | Replace "string typing" with classes

概要

Replace "string typing" with classes

前提

Confident Rubyではメソッド内の処理を次のように分類しています。
・Collecting Inputs(引数チェック、変換など)
・Performing Work(主処理)
・Delivering Output(戻り値に関わる処理)
・Handling Failure(例外処理)

当記事は上記のうち、Collecting Inputsに関する話です。

詳細

状況

入力データは特定のフォーマットの文字列。
Stringの中身は様々なステートメントの分岐がある。

概要

特別な意味を持つ文字列をユーザー定義の型に置換する。

理由

多態性に傾いた意思決定を行うことが、
オブジェクトの設計を明確にし、不要な冗長性やミスの機会を減らすことができるため。

サンプルコード仕様

RPGの戦士を表したクラスの状態を3つ定義します。
元気=Normal
毒=Poison
呪い=Curse

サンプルコード(ステータスごとに分岐したバージョン)

class Fighter
  def change_status(status)
    case status
    when :normal
      @status = "元気"
    when :poison
      @status = ""
    when :curse
      @status = "呪い"
    else
      fail 'invalid status'
    end
  end

  def show_status
    "ステータスは#{@status}"
  end
end

f = Fighter.new
f.change_status(:normal)
puts f.show_status
f.change_status(:poison)
puts f.show_status
f.change_status(:curse)
puts f.show_status

出力

ステータスは元気
ステータスは毒
ステータスは呪い

サンプルコード(文字列をクラスに変換したバージョン)

class Fighter
  [
    {klass: :Normal, status: "元気"},
    {klass: :Poison, status: ""},
    {klass: :Curse, status: "呪い"},
  ].each do |klass_status|
    const_set(klass_status[:klass], Class.new do |klass|
      define_method :status do
        klass_status[:status]
      end
    end)
  end

  def change_status(status)
    @status = self.class.const_get(status.to_s.capitalize).new.status
  end

  def show_status
    "ステータスは#{@status}"
  end
end

f = Fighter.new
f.change_status(:normal)
puts f.show_status
f.change_status(:poison)
puts f.show_status
f.change_status(:curse)
puts f.show_status

出力

ステータスは元気
ステータスは毒
ステータスは呪い