見出し画像

【95】【Rails】リファクタリングトレーニング_継承からコンポジションに変換

この記事を読むと問題のあるコードや改善の余地があるコードを学び、リファクタリングする能力を養うことができます。

継承のコードをコンポジションに変換してみましょう。

今回は下記の継承を用いられているコードを、コンポジションにリファクタリングしてみましょう。

class Bicycle
 attr_reader :size, :parts

 def initialize(args = {})
   @size = args[:size]
   @parts = args[:parts]
 end
 def spares
   parts.spares
 end
end

class Parts
 attr_reader :chain, :tire_size

 def initialize(args={})
   @chain = chain || default_chain
   @tire_size = tire_size || default_tire_size
   post_initialize(args)
 end

 def spares
   {
       tire_size: tire_size,
       chain: chain
   }.merge(local_spares)
 end

 def post_initialize(args)
   nil
 end

 def local_spares
   {}
 end

 def default_chain
   "10-speed"
 end

 def default_tire_size
   raise NotImplementedError
 end
end

class RoadBikeParts < Parts
 attr_reader :tape_color

 def post_initialize(args)
   @tape_color = args[:tape_color]
 end

 def local_spares
   {tape_color: tape_color}
 end

 def default_tire_size
   "23"
 end
end

class MountainBikeParts < Parts
 attr_reader :front_shock, :rear_shock

 def post_initialize(args)
   @front_shock = args[:front_shock]
   @rear_shock = args[:rear_shock]
 end

 def local_spares
   {rear_shock: rear_shock}
 end

 def default_tire_size
   "2.1"
 end
end

テスト

require_relative '5_3_1_before_refactoring'


RSpec.describe "Bicycleモデル" do
 mountain_bike =
     Bicycle.new(
         size: "L",
         parts: MountainBikeParts.new(rear_shock: "Fox")
     )
 it '#spares' do
   expect(mountain_bike.spares).to eq({:chain=>"10-speed", :rear_shock=>"Fox", :tire_size=>"2.1"})
 end
end

そもそもなぜコンポジションに?

コンポジションについてはこの記事で

リファクタリング

class Bicycle
 attr_reader :size, :parts

 def initialize(args = {})
   @size = args[:size]
   @parts = args[:parts]
 end
 def spares
   parts.spares
 end
end

class Parts
 attr_reader :parts

 def initialize(parts)
   @parts = parts
 end

 def spares
   parts.select{|part| part.needs_spare}
 end
end

class Part
 attr_reader :name, :description, :needs_spare

 def initialize(args)
   @name = args[:name]
   @description = args[:description]
   @needs_spare = args.fetch(:needs_spare,true)
 end
end

テスト

require_relative '5_3_2_refactoring'


RSpec.describe "Bicycleモデル" do
 chain = Part.new(name: "chain",description: "10-speed")
 mount_tire =
     Part.new(name: "tire_size",description: "2.1")
 rear_shock =
     Part.new(name: "rear_shock",description: "Foc")
 front_shock =
     Part.new(name: "front_shock",
              description: "Manitou",
              needs_spare: false)

 mountain_bike_parts =
     Parts.new([chain,mount_tire,rear_shock,front_shock])
 bike =
     Bicycle.new(
         size: "L",
         parts: mountain_bike_parts
     )

 spares = bike.spares.map do |part|
   {"#{part.name}".to_sym =>"#{part.description}"}
 end

 it '#spares' do
   expect(spares).to eq  [{:chain=>"10-speed"}, {:tire_size=>"2.1"}, {:rear_shock=>"Foc"}]

 end
end

さらに改善できます

注意点!

リファクタリング後のコードが完全な形になっていっているわけではありません。前よりかは良くなったと捉えてください。

 関連する記事

参考文献

オブジェクト指向設計実践ガイド
~Rubyでわかる 進化しつづける柔軟なアプリケーションの育て方

最後に
私がブログを書く目的は、素晴らしい本や、素晴らしい方々の技術記事を知って頂きたいからです。ぜひ、上記の参考文献を見て下さい。(noteなので広告とかは一切ありません。)

現在、株式会社grabssに行くために最後の悪あがきをしています!!
現在の進行状況
この記事は95件目の投稿。目標達成!!!!
目標再設定
20日までに100件目指す!!(95件目)
20日超えたが、寝るまでは20日営業日!!(まだ寝てない、ちょっと寝##峠を超え目が覚めた!)
気持ちは20日!

よろしければ、スキボタン及びサポートお願いします。勉強の励みになります。

この記事が気に入ったらサポートをしてみませんか?