【Ruby】コンポジションと委譲の関係

Ruby
記事内に広告が含まれています。

コンポジションと委譲は、どちらも『あるオブジェクトが別のオブジェクトの機能を使う』という文脈で登場するため、混同しやすい概念です。
しかし、この2つは同じ意味ではありません。
本記事では、この両者の関係性について説明します。

コンポジション

コンポジション(Composition)とは、オブジェクトが別のオブジェクトを部品として持つことで、全体としての機能を作り上げるという設計思想です。
これは「has-a」(〜を持っている)の関係で表現されます。

例えば、車はエンジンやタイヤなど、複数の部品から成り立っています。
車のクラスを設計するとき、エンジンやタイヤのクラスを継承するのではなく、それらのインスタンスを「部品」として持つように実装します。
これにより、部品の再利用や交換が容易になります。

class Engine
  def start
    puts "エンジンをかけます。"
  end
end

class Car
  def initialize
    # CarはEngineを「持っている」
    @engine = Engine.new
  end
end

このコードは、CarクラスがEngineクラスをコンポジションしています。

委譲

委譲(Delegation)とは、あるオブジェクトが受け取ったメソッド呼び出しを、保持している別のオブジェクトに任せるという、具体的なプログラミングのテクニックです。

Carクラスに「エンジンをかける」というstartメソッドを追加したいとします。
しかし、実際にエンジンをかける処理を行うのは、Carクラスが持っているEngineオブジェクトです。

ここで登場するのが「委譲」です。
Carクラスのstartメソッドの中で、Engineオブジェクトのstartメソッドを呼び出します。

class Car
  def initialize
    @engine = Engine.new
  end

  # Engineオブジェクトにstartメソッドの処理を「委譲」
  def start
    @engine.start
  end
end

car = Car.new
car.start # => "エンジンをかけます。"

このコードは、CarstartメソッドがEnginestartメソッドに処理を委譲しています。

DIと委譲

委譲は、コンポジションと組み合わせるだけではありません。
例えば DI(依存性注入)と組み合わせて使われることもあります。

DI は「依存するオブジェクトを外部から注入する設計」です。

class Car
  def initialize(engine)
    # Engineを自分で生成せず、外部から受け取る(=DI)
    @engine = engine
  end

  def start
    # start処理はEngineに任せる(=委譲)
    @engine.start
  end
end

car = Car.new(Engine.new)
car.start # => "エンジンをかけます。"

このコードは、CarクラスがEngineを自分でnewせず、外部から注入しています。
このように、委譲とは「別のオブジェクトに処理を任せるテクニック」です。

まとめ

  • コンポジション:設計の考え方。「has-a」の関係でオブジェクト同士を組み合わせる
  • 委譲:実装のテクニック。別のオブジェクトに処理を任せる

最後までお読みいただきありがとうございました。

皆さんからのコメントやSNSでのシェア、嬉しい投稿をいただくと本当に励みになります。

もしこの記事が気に入ったら感想をコメントやSNSでシェアしていただけると嬉しいです。

皆さんの声を聞かせてくださいね!

Ruby
tetsuをフォローする
簿記はじめるってよ

コメント

タイトルとURLをコピーしました