OpenStructを用いる　オブジェクト指向設計実践ガイドより

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

  def initialize(args = {})
    @size = args[:size]
    @parts = args[:parts]
  end
  def spares
    parts.spares
  end
end
require 'forwardable'
class Parts
  extend Forwardable
  def_delegators :@parts, :size,:each
  include Enumerable
  def initialize(parts)
    @parts = parts
  end

  def spares
    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
module PartsFactory
  def self.build(config,part_class = Part,parts_class = Parts)
    parts_class.new(
      config.collect{ |part_config|
        part_class.new(
          name: part_config[0],
          description: part_config[1],
          needs_spare: part_config.fetch(2,true)
        )
      }
    )
  end
end
road_config = [
  ["chain","10-speed"],
  ["tire_size","23"],
  ["tape_color","Fox"]
]
mountain_config =
  [
    ["chain","10-speed"],
    ["tire_size","Manitou",false ],
    ["rear_shock","Fox"]
  ]

road_bike =
  Bicycle.new(
    size: 'L',
    parts: PartsFactory.build(road_config)
  )
road_bike.spares
mountain_bike =
  Bicycle.new(
    size: "L",
    parts: PartsFactory.build(mountain_config)
  )
mountain_bike.spares
mountain_bike.parts.size
```
##考察
PartsFactoryモジュールのbuildメソッドが複雑ですっきりさせたいですね。
また、PartクラスとPartsFactoryモジュールが重複しています。
##リファクタリング後
```ruby
class Bicycle
  attr_reader :size, :parts

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

  def spares
    parts.spares
  end
end

require 'forwardable'
class Parts
  extend Forwardable
  def_delegators :@parts, :size,:each
  include Enumerable

  def initialize(parts)
    @parts = parts
  end

  def spares
    select {|part| part.needs_spare}
  end
end
require 'ostruct'
module PartsFactory
  def self.build(config,parts_class = Parts)
    parts_class.new(
      config.collect{|part_config|
        create_part(part_config)
      }
    )
  end
  def self.create_part(part_config)
    OpenStruct.new(
      name: part_config[0],
      description: part_config[1],
      needs_spare: part_config.fetch(2,true)
    )
  end
end
road_config = [
  ["chain","10-speed"],
  ["tire_size","23"],
  ["tape_color","Fox"]
]
mountain_config =
  [
    ["chain","10-speed"],
    ["tire_size","Manitou",false ],
    ["rear_shock","Fox"]
  ]

road_bike =
  Bicycle.new(
    size: 'L',
    parts: PartsFactory.build(road_config)
  )
road_bike.spares
mountain_bike =
  Bicycle.new(
    size: "L",
    parts: PartsFactory.build(mountain_config)
  )
mountain_bike.spares
mountain_bike.parts.size
```
##OpenStruct
新たにcreate_partメソッドを作り、buildメソッドを簡潔にしました。
そして、OpenStructを用いることによって、Partクラスを全て削除できました！
#後記
OpenStructのより詳しい説明を後日加筆しようか考えてます

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