Help us understand the problem. What is going on with this article?

Rubyによるデザインパターン5原則

More than 5 years have passed since last update.

概要

改めて基本を学ぶ。
Rubyによるデザインパターン第1章。

デザインパターンとは

  • プログラミングにおいて繰り返し現れる問題に対する、適切解のパターン。
  • 無駄無く設計されたオブジェクト指向プログラムの実現をサポート。

パターンとしてカタログ化されていることで
車輪の再発明を防ぐ

デザインパターンの根底にある5つの考え

  • 変わるものを変わらないものから分離する
  • プログラムはインターフェイスに対して行う(実装に対して行わない)
  • 継承より集約
  • 委譲、委譲、委譲
  • 必要になるまで作るな(YAGNI)

変わるものを変わらないものから分離する

ソフトウェアの仕様には必ず変更が加わるもの。
変わるものと変わらないものを分離しておくことで、
「仕様の変更」に対して「システムの変更」を出来る限り局所的にする。

プログラムはインターフェイスに対して行う(実装に対して行わない)

可能な限り「一般的・抽象的なもの」に対してプログラミングすること。
(ここで言うインターフェイスは、Javaの組み込み構文としてのインターフェイスではなく、
より広いレベルで「抽象度を高めたもの」を意味する。)

これにより、全体のコードの結合度を下げる。

具体性が高く、密結合なコード

if is_car?
  my_car = Car.new
  my_car.drive(200)
else
  my_plane = AirPlane.new
  my_plane.fly(200)
end

乗り物が増える度にコード全体に変更が必要(変更に弱い)。

抽象度が高く、疎結合なコード

my_vehicle = get_vehicle
my_vehicle.travel(200)

乗り物の数が増えても本コードに変更を加える必要はない(変更に強い)。

継承より集約

継承は望ましくないつながりを作ってしまう。

具体的には

  • サブクラスの振る舞いは、スーパークラスの振る舞いに依存する。
  • サブクラスからスーパークラスの中身を覗くことが出来る。
class Vehicle
  def start_engine
    # エンジンを動かすためのもろもろの処理..
  end

  def stop_engine
    # エンジンを止めるためのもろもろの処理..
  end
end

class Car < Vehicle
  def drive
    start_engine
    # driving..
    stop_engine
  end
end
  • Carからエンジンの実装が丸見え
  • エンジンを使用しない乗り物を作りたい場合は大改造が必要

→変わりやすい部分(Engine)を変わりにくい部分(Vehicle)から分離できていない。

代替案

集約を使う。
つまり、

オブジェクトに、「他のオブジェクトに対する参照」を持たせる。

オブジェクトが何かの一種である(is-a-kind-of)関係は避けて、
何かを持っている(has-a)関係にする。

Car has a Engineの例

class Car
  def initialize
    @engine = Engine.new
  end

  def drive
    @engine.start
    # driving..
    @engine.stop
  end
end

class Engine
  def start
    # エンジンを動かすためのもろもろの処理..
  end

  def stop
    # エンジンを止めるためのもろもろの処理..
  end
end

これでEngineがVehicleから分離され、またカプセル化された。

これにより、Engineの手軽な切り替えが可能に。

class Car
  def initialize
    @engine = GasolineEngine.new
  end

  def drive
    @engine.start
    # ガソリンエンジンでドライブ..
    switch_to_diesel
    # ディーゼルエンジンでドライブ..
    @engine.stop
  end

  def switch_to_diesel
    @engine = DieselEngine.new
  end
end

委譲、委譲、委譲

委譲(delegation)

(継承パターンと同じように)start_engineとstop_engineを
クラスの外に公開したいこともある。

そんな場合でも、処理の実態はEngineクラスに任せてしまう。

class Car
  def initialize
    @engine = GasolineEngine.new
  end

  def drive
    @engine.start
    # driving..
    @engine.stop
  end

  def switch_to_diesel
    @engine = DieselEngine.new
  end

  def start_engine
    @eigine.start  # Engineクラスに任せる
  end

  def stop_engine
    @eigine.stop  # Engineクラスに任せる
  end
end

これで「継承より集約」を実現しつつ、継承時と同じ機能を持つクラスが作成できた。
つまり、

集約と委譲の組み合わせは、強力かつ柔軟な継承の代替手段。

※ start_engineやstop_engineは委譲のために書かなければならない無駄なコードに思えるが、
method_missing等の利用で解決できる。
これはProxyパターンで別途詳細する。

必要になるまで作るな(YAGNI/You Ain't Gonna Need It.)

「将来使うかも」は、大抵使わない。

いたずらに柔軟性を持たせようとオーバーエンジニアリングして
コードの複雑性を増していては、本末転倒。

デザインパターン自身は目的ではない。
問題を解決し、目的を達成するための手段として役立てるべきであり、それ以上のものではない。

デザインパターンを考える上での戒め。

以上5原則を前提に

各パターンを見ていく。

【Template Method】-テンプレは準備した、あとはお好きに-
http://qiita.com/kidachi_/items/7c2a80bfc8a87a05051f

【Strategy】-取り替え可能パーツ群を戦略的に利用せよ-
http://qiita.com/kidachi_/items/02f8f6df955ba1d0e93b

【Observer】-本日のニュースをお届けします-
http://qiita.com/kidachi_/items/ce18d2a926c558159689

【Composite】 -世界は再帰的(部分は全体、全体は部分)-
http://qiita.com/kidachi_/items/6cb73b2bbc875e9bef6d

【Iterator】-君の子供たちに伝えたいのだけど-
http://qiita.com/kidachi_/items/afa4c6c29a6eb6be487a

その他WIP.

kidach1
Qiitaの運営方針に疑問があるため、基本的に今後の投稿は考えていません。 主に https://twitter.com/kidach1 で活動報告しています。
aktsk
株式会社アカツキは、スマートフォンゲームの企画開発を中心に事業を展開しております。創業以来全てのゲームを内製しているため、高い技術ノウハウが蓄積されています。今後は、新規事業の立ち上げも行ってまいります。
http://aktsk.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした