LoginSignup
0
0

More than 1 year has passed since last update.

フックメッセージを使う オブジェクト指向設計実践ガイドより

Last updated at Posted at 2021-06-15

はじめに

本題はここフックメッセージからです

読者対象

読者対象はプログラミング初学者です。
といっても全くの初学者ではなく、Railsチュートリアルを終えたレベルと定義します。

オブジェクト指向設計実践ガイド

オブエジェクト指向設計実践ガイドの記事は、他の方も書いてありますが、
一度に全部まとめたものが多かったです。
この記事は、オブエジェクト指向らしく、各章ごとに、単一責任に、シンプルさを意識して書きました。
余談ですが、とある弁護士が弁護士は六法全書を丸暗記してないが、各条文を見ただけで、関係ある条文、知識を思い出すそうです。
この記事は、オブジェクト指向設計実践ガイドってこんなこと書いてあったなーと思いだすための記事でもあります。
また、オブエジェクト指向設計実践ガイドを読んだことがなくても、こういうことが書いてあるとのかー、とさわりだけでも理解して頂けたら幸いです。

オブジェクト指向設計実践ガイドで得た3つのポイント

リファクタリング前のコードを読み、コードの危うさを察知できる。
リファクタリングするために、より抽象的なコードの書き方を学べる。
gemなどの抽象的なコードを読解できる。

一問一答

一問一答風の構成にしています。
リファクタリング前のコードを読み、コードの危うさ、嗅覚を養っていきましょう。
その後、リファクタリング前のコードの危うさを説明し、自分なりにリファクタリングしたコードを書いてみましょう。
最後に、もう一度、リファクタリング前のコードと、リファクタリング後のコードを読み比べ、
抽象的な思考、抽象的な書き方を共に学んでいきましょう。

フックメッセージ

今回は第6章フックメッセージについて説明します。
下記コードを読んで、このコードの危うさを説明し、自分なりにリファクタリングしたコードを書けるレベルに達しているなら、
オブエジェクト指向設計実践ガイドの第6章 「継承によって振る舞いを獲得する」、
この章を理解していると言えるでしょう。

注意点

下記コードは第6章の後半とあって、それなりにリファクタリングされています。
絶対にダメな書き方というわけではありませんので注意して下さい。

リファクタリング前

class Bicycle
  attr_reader :size,:chain,:tire_size
  def initialize(args)
    @size = args[:size]
    @chain = args[:chain] || default_chain
    @tire_size = args[:tire_size] || default_tire_size
  end
  def spares
    {
      tire_size: tire_size,
      chain: chain
    }
  end
  def default_chain
    "10-speed"
  end
end
class RoadBike < Bicycle
  attr_reader :tape_color

  def initialize(args)
    @tape_color = args[:tape_color]
    super(args)
  end
  def spares
    super.merge({tape_color: tape_color})
  end

  def default_tire_size
    "23"
  end
end
class MountainBike < Bicycle
  attr_reader :front_shock,:rear_shock

  def initialize(args)
    @front_shock = args[:front_shock]
    @rear_shock = args[:rear_shock]
    super(args)
  end
  def spares
    super.merge({rear_shock: rear_shock})
  end
  def default_tire_size
    "2.1"
  end
end
bike = RoadBike.new(size: "L",tape_color: "red")
bike.size
bike.spares

このコードの危うさ

新たにサブクラスが作られたとします。
このサブクラスでdefault_tire_sizeが書かれてなかったら、エラーが発生します。
また、superの書き忘れで思わぬエラーが発生します。
サブクラスどんどん増えていくにつれて、上記のエラー発生率が高くなります。

リファクタリング後

class Bicycle
  attr_reader :size,:chain,:tire_size
  def initialize(args)
    @size = args[:size]
    @chain = args[:chain] || default_chain
    @tire_size = args[:tire_size] || default_tire_size
    post_initialize(args)
  end
  def post_initialize(args)
    nil
  end
  def spares
    {
      tire_size: tire_size,
      chain: chain
    }.merge(local_spares)
  end
  def local_spares
    {}
  end
  def default_chain
    "10-speed"
  end
  # 適切なエラーを表示するため
  def default_tire_size
    raise NotImplementedError
  end
end
class RoadBike < Bicycle
  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 MountainBike < Bicycle
  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
bike = RoadBike.new(size: "L",tape_color: "red")
bike.size
bike.spares

フックメッセージ

default_tire_sizeのエラー処理を親クラスに記載しました。
ここから本題です。
親クラスのBicycleが各サブクラスにフックメッセージを送るようにしました。(post_initialize(args))
フックメッセージを使う目的は、

サブクラスからアルゴリズムの知識を取り除き、代わりにスーパークラスに制御を戻すことです。
(オブジェクト指向実践ガイド p172)

今回実装によって、superの書き忘れによるエラーを防ぐことができます。
また各サブクラスのコードの可読性も増しました。
新しいサブクラスを作る際も、リファクタリング前より簡潔に書けるようになります。

参考文献

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

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0