委譲
CoddyのLuaジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 50/70。
ある object を別の object の中に格納することは、まだ最初の一歩にすぎません。コンポジションの真の力は、外側の object が inner コンポーネントに 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の公開インターフェースは変わりません。変わるのは内部の委譲だけです。
チャレンジ
簡単委譲を示す 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 が与えられます。
- speaker の音量(数値)
- music player の brand(string)
- 再生する track name(string)
output には、player が speaker と連携している様子が示されます。
{brand} player starting...
Playing "{trackName}" at volume {volume}
{brand} player stoppedたとえば、inputs が 75、SoundMax、Summer Vibes の場合、output は次のようになります。
SoundMax player starting...
Playing "Summer Vibes" at volume 75
SoundMax player stoppedMusicPlayer は 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メソッドを呼び出す
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
自分で練習してみよう: Luaオンラインコンパイラ