Menu
Coddy logo textTech

委譲

CoddyのLuaジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 50/70。

ある object を別の object の中に格納することは、まだ最初の一歩にすぎません。コンポジションの真の力は、外側の objectinner コンポーネントに method 呼び出しを転送する委譲から生まれます。

car を始動することを考えてみてください。ボンネットの下に手を入れて、手動で engine を回すわけではありません。代わりに key を回せば、car が内部ですべてを handles します。

コードでは、これは Car クラスが、実際の処理をエンジンに委譲する単純な :start() メソッドを提供することを意味します。

function Car:start()
    print("Turning the key...")
    self.engine:run()  -- 内部オブジェクトに委譲する
end

車はエンジンがどのように動くのかを知る必要はありません。車はエンジンに仕事をするよう伝えるだけです。これにより、責任が分離されます。Engineクラスはエンジンのロジックを処理し、Carは各要素を調整します。

function Engine:run()
    print("Engine running at " .. self.horsepower .. " HP")
end

local engine = Engine:new(250)
local car = Car:new("Coupe", engine)
car:start()
-- 出力:
-- キーを回しています...
-- エンジンが 250 HP で稼働中

委譲は、あなたのclassの利用者にクリーンなインターフェースを提供します。利用者は内部の部品ではなく、carとやり取りします。後から別のengineの実装に差し替えても、carの公開インターフェースは変わりません。変わるのは内部の委譲だけです。

challenge icon

チャレンジ

簡単

委譲を示す music player システムを作ってみましょう!Speaker コンポーネントと、それを内包する MusicPlayer を作成します。player は sound output を直接処理せず、代わりにその責任を内部の speaker に委譲します。

コードを3つのファイルに分けて整理します。

  • Speaker.lua:音量レベルを保存するコンストラクター :new(volume) を持つ Speaker class を作成します。Playing "{trackName}" at volume {volume} と表示する :playSound(trackName) method を含めます。
  • MusicPlayer.lua:コンストラクター :new(brand, speaker) が brand 名と Speaker object を受け取る MusicPlayer class を作成します。player は speaker を自身の内部に保存します。次の method を含めます。
    • :play(trackName){brand} player starting... と表示してから、speaker の :playSound() method に委譲します。
    • :stop(){brand} player stopped と表示します。
  • main.lua:everything をまとめます!speaker の音量、player の brand、再生する track name の inputs を読み取ります。まず Speaker を作成し、それを MusicPlayer のコンストラクターに渡します。track name を使って player の :play() method を呼び出し、その後 :stop() を呼び出します。

3つの inputs が与えられます。

  1. speaker の音量(数値)
  2. music player の brand(string)
  3. 再生する track name(string)

output には、player が speaker と連携している様子が示されます。

{brand} player starting...
Playing "{trackName}" at volume {volume}
{brand} player stopped

たとえば、inputs が 75SoundMaxSummer Vibes の場合、output は次のようになります。

SoundMax player starting...
Playing "Summer Vibes" at volume 75
SoundMax player stopped

MusicPlayer は sound の 方法 を知らないことに注目してください。単に、その部分を処理するよう speaker に指示しているだけです。これが委譲の実例です。外側の object がすっきりしたインターフェースを提供し、inner component が専門的な作業を担当します。

自分で試してみよう

-- main.lua
-- すべてをまとめよう!

local Speaker = require('Speaker')
local MusicPlayer = require('MusicPlayer')

-- 入力を読み取る
local volume = tonumber(io.read())
local brand = io.read()
local trackName = io.read()

-- TODO: 指定されたvolumeでSpeakerを作成する

-- TODO: brandとspeakerでMusicPlayerを作成する

-- TODO: track nameを指定してplayerのplayメソッドを呼び出す

-- TODO: playerのstopメソッドを呼び出す
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

オブジェクト指向プログラミングのすべてのレッスン

自分で練習してみよう: Luaオンラインコンパイラ