コンポジション　オブジェクト指向設計実践ガイドより

#はじめに
本題は[ここコンポジション](#コンポジション)からです
##読者対象
読者対象はプログラミング初学者です。
といっても全くの初学者ではなく、Railsチュートリアルを終えたレベルと定義します。
##オブジェクト指向設計実践ガイド
**オブエジェクト指向設計実践ガイド**の記事は、他の方も書いてありますが、
一度に全部まとめたものが多かったです。
この記事は、オブエジェクト指向らしく、各章ごとに、単一責任に、シンプルさを意識して書きました。
余談ですが、とある弁護士が弁護士は六法全書を丸暗記してないが、各条文を見ただけで、関係ある条文、知識を思い出すそうです。
この記事は、**オブジェクト指向設計実践ガイド**ってこんなこと書いてあったなーと思いだすための記事でもあります。
また、**オブエジェクト指向設計実践ガイド**を読んだことがなくても、こういうことが書いてあるとのかー、とさわりだけでも理解して頂けたら幸いです。
##オブジェクト指向設計実践ガイドで得た3つのポイント
**リファクタリング前のコードを読み、コードの危うさを察知できる。**
**リファクタリングするために、より抽象的なコードの書き方を学べる。**
**gemなどの抽象的なコードを読解できる。**
##一問一答
一問一答風の構成にしています。
リファクタリング前のコードを読み、コードの危うさ、嗅覚を養っていきましょう。
その後、リファクタリング前のコードの危うさを説明し、自分なりにリファクタリングしたコードを書いてみましょう。
最後に、もう一度、リファクタリング前のコードと、リファクタリング後のコードを読み比べ、
抽象的な思考、抽象的な書き方を共に学んでいきましょう。
#コンポジション
今回は**第8章コンポジション**について説明します。
下記リファクタリング前のコードは継承、フックメッセージが適切に使われおり、十分に使えるコードです。
今回は、継承を使わない観点、コンポジションという観点からリファクタリングして見て下さい。
オブエジェクト指向実践ガイドの第8章　「コンポジションでオブジェクトを組み合わせる」、
この章を一部理解していると言えるでしょう。（残りの知識は別記事に書きます）
##リファクタリング前
```ruby
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
road_bike = Bicycle.new(size: "L",parts: RoadBikeParts.new(tape_color: "red"))
road_bike.size
road_bike.spares

```
###継承を使わない書き方
Partsクラスを各サブクラスが継承しています。
継承を使わない観点からリファクタリングしてみましょう。
##リファクタリング後
```ruby
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
chain = Part.new(name: "chain",description: "10-speed")
road_tire =
  Part.new(name: "tire_size",description: "23")
tape =
  Part.new(name: "tape",description: "red")
mountain_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)
road_bike_parts =
  Parts.new([chain,road_tire,tape])
road_bike =
  Bicycle.new(
    size: "L",
    parts:   road_bike_parts
  )
road_bike.size
road_bike.spares
```
##コンポジション
かなりすっきりしましたね！
ただ、インスタンス作成の処理がごちゃごちゃしているので、
まだ改善の余地はあります。（後日、別記事で書きます）
継承使って書くか？
コンポジションで書くか？
私の現在のレベルではうまく説明できません。
引用します。
>一般的なルールとしては、直面した問題がコンポジションによって解決できるなら、
コンポジションで解決することを優先するべきです。(中略)
継承がより良い選択肢であるのは、継承が低いリスクで高い利益を生み出してくれるときです。
　『オブジェクト指向設計実践ガイド』 p229

#参考文献
[オブエジェクト指向設計実践ガイド　～Rubyでわかる 進化しつづける柔軟なアプリケーションの育て方](https://gihyo.jp/book/2016/978-4-7741-8361-9)