こんにちは。
最近 リファクタリング Rubyエディション を読みました。本書はリファクタリングの様々なパターンをRubyのサンプルコードを使って解説している名著です。
実務でも活かせそうなパターンが多く紹介されていたので、いいなと思ったパターンを1つずつブログにまとめています。
今回はその第8弾で「抽象スーパークラスからモジュールへ」についてまとめました。
オリジナルの Ruby のサンプルコードを使って説明しています。
前回の「サンドイッチメソッドの抽出」のまとめはこちらです。
サンドイッチメソッドの抽出【リファクタリング Rubyエディションまとめ7】 - 銀行員からのRailsエンジニア
抽象スーパークラスからモジュールへ とは
サンプルコード
リファクタリング前
まずはリファクタリング前のコードです。
class Item def initialize(name, origin_country = nil) @name = name @origin_country = origin_country end def description puts "商品名:#{@name} / 補足:#{additional_description}" end end class DomesticItem < Item def additional_description '国内産です' end end class ImportedItem < Item def additional_description "#{@origin_country}で作られました" end end
商品(Item)クラスを、国内産商品(DomesticItem)クラスと輸入商品(ImportedItem)クラスが継承しています。
次のように実行すると
DomesticItem.new('イヤホン').description ImportedItem.new('スマートフォン', 'アメリカ').description
次の結果になります。
商品名:イヤホン / 補足:国内産です 商品名:スマートフォン / 補足:アメリカで作られました
このコードの問題点としては、スーパークラスである Item クラスのインスタンス化は可能なものの、Item クラスのインスタンスで description メソッドを呼び出すと additional_description メソッドが定義されていないためエラーになってしまう点です。
リファクタリング後
「抽象スーパークラスからモジュールへ」を使ってリファクタリングをすると下記のようになります。
module Item def initialize(name, origin_country = nil) @name = name @origin_country = origin_country end def description puts "商品名:#{@name} / 補足:#{additional_description}" end end class DomesticItem include Item def additional_description '国内産です' end end class ImportedItem include Item def additional_description "#{@origin_country}で作られました" end end
変更点は、継承関係を解消して、モジュール化した Item クラスをそれぞれのクラスで include したのみです。
実行の仕方、結果は先ほどと同じになります。
おわりに
ここまでお読みいただきありがとうございます。
このリファクタリングはデザインパターンの1つである「テンプレートメソッドパターン」で使えそうだなーと思ったので、今回のサンプルコードは、テンプレートメソッドパターンを使ったものにしています。
テンプレートメソッドパターンについて詳しく知りたい方は、合わせてこちらをご覧ください。
ysk-pro.hatenablog.com
リファクタリング Rubyエディションでは、この記事の内容に加えてクラスメソッドが存在する場合のリファクタリングの仕方についても触れられていて参考になったので、ご興味ある方は是非ご覧ください。
- 作者:ジェイ・フィールズ,シェーン・ハービー,マーティン・ファウラー
- 発売日: 2020/03/21
- メディア: 単行本
次回はまた違うパターンをまとめていきます!
前回の「サンドイッチメソッドの抽出」のまとめはこちらです。是非合わせてご覧ください。
ysk-pro.hatenablog.com