空飛ぶたまごエンジニア

韓国進出を夢見るエンジニアのブログ

10月3日の日記

今日の学び

リファクタリング: Rubyエディション

第7章は オブジェクト間でのメンバの移動 をテーマに、リファクタリングのテクニックがまとめられている。

全部で6つのテクニックが紹介されている。

  • Move Method
  • Move Field
  • Extract Class
  • Inline Class
  • Hide Delegate
  • Remove Middle Man

Move Field

要約

フィールドが、他クラスでよく使われていたら、最もよく使われているクラスにフィールドを移動する

# リファクタリング前
class Employee
  def initialize(bonus_rate)
    @bonus_rate = bonus_rate
  end

  def bonus
    @bonus_rate * base_salary
  end
end

# リファクタリング後
class Employee
  def initialize(employee_type)
    @employee_type = employee_type
  end

  def bonus(base_salary)
    @employee_type.bonus_rate * base_salary
  end
end

class EmployeeType
  attr_accessor :bonus_rate

  def initialize(bonus_rate)
    @bonus_rate = bonus_rate
  end
end

※ 注意: 上記サンプルは、 bonus_rate フィールドが Account クラスではなく AccountType クラスでよく使われるようになることが前提となっている

説明

  • フィールドは最もよく使われているクラスに定義する

備考

  • 以前までは正しかった実装が、今では誤った実装になりうる
    • 仕様が変われば、リファクタリングで実装し直せばいいだけ
    • 問題は誤った実装のまま、何も対策を打たないこと

所感

フィールドは最もよく使われているクラスに定義することで、コード量が減ることを実感。

コード量が少なくなれば、それだけ人間が読むコードの量も減るし、結果的に効率的な開発に繋がるのだろうと思った。

調べたところ

ここでいうフィールドとは?

クラス内のインスタンス変数のことを差すようだった

アクセサ

クラス内にインスタンス変数を定義するだけでは、そのクラスのインスタンスから定義したインスタンス変数にアクセスできない

class Person
  def initialize(name)
    @name = name
  end
end

person = Person.new("Bob")
person.name
# => NoMethodError: undefined method `name' for #<Person:0x00007fd0faaf99e8 @name="Bob">

上記のインスタンス変数にアクセスするためには、以下のようなゲッターとセッターを実装する必要がある

class Person
  def initialize(name)
    @name = name
  end

  # ↓ これがゲッター
  def name
    @name
  end

  # ↓ これがセッター
  def name=(val)
    @name = val
  end
end

person = Person.new("Bob")
person.name
# => "Bob"

person.name = "John"
person.name
# => "John"

Ruby には attr_readerattr_writerattr_accessor といったアクセスメソッドが用意されていて、ゲッターとセッターを簡単に実装できる

定義式 機能
attr_reader: 変数名 参照が可能
attr_writer :変数名 更新が可能
attr_accessor :変数名 参照と更新が可能
class Person
  attr_accessor :name

  def initialize(name)
    @name = name
  end
end

person = Person.new("Bob")
person.name
# => "Bob"

person.name = "John"
person.name
# => "John"