親メソッドの呼び出し
CoddyのLuaジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 38/70。
メソッドを完全にオーバーライドしたいとは限らない場合があります。代わりに、extendsしてparentのbehaviorを拡張したいことがあります。つまり、parentが行うことを実行してから、さらに何かを追加するということです。これを実現するには、childのオーバーライド内からparentのmethodを直接呼び出します。
このテクニックでは、parentクラス名とともにドット構文を使用し、最初の引数としてselfを明示的に渡します:
local Animal = {}
Animal.__index = Animal
function Animal:new(name)
local obj = {name = name}
setmetatable(obj, Animal)
return obj
end
function Animal:speak()
print(self.name .. " makes a sound")
end
-- Dog は親の振る舞いを拡張する
local Dog = {}
Dog.__index = Dog
setmetatable(Dog, {__index = Animal})
function Dog:new(name)
local obj = Animal.new(Animal, name)
setmetatable(obj, Dog)
return obj
end
function Dog:speak()
Animal.speak(self) -- 親のメソッドを先に呼び出す
print(self.name .. " wags tail happily")
end重要な行は Animal.speak(self) です。親クラスに対してドット構文を使い、self を手動で渡すことで、独自の動作を追加する前に元のメソッドを呼び出します。
local buddy = Dog:new("Buddy")
buddy:speak()
-- 出力:
-- Buddy が音を出す
-- Buddy が嬉しそうにしっぽを振るこのパターンは、重複したくない重要な処理を親のメソッドが行う場合に便利です。子は、親のロジックを最初に、最後に、あるいは自身のコードの途中で実行することもでき、behavior の組み合わせ方を完全に制御できます。
チャレンジ
簡単通常の Person の behavior を拡張する FormalPerson を使って、greeting system を構築しましょう!person が自分自身を紹介する方法を完全に置き換えるのではなく、formal version はまず標準の introduction を行い、その後に丁寧なひと言を追加します。
コードは次の3つのファイルに分けて構成します。
Person.lua: person の名前を保存する:new(name)constructor を持つ Base class です。person の名前に続けてsays hiを prints する:introduce()method も含めます。これは拡張される Base behavior です。FormalPerson.lua: Person から継承する Child class です。その Constructor では、名前を処理するために parent の Constructor を Call します。:introduce()method を Override しますが、parent の behavior を完全に置き換えるのではなく、まず parent の method を Call するためにPerson.introduce(self)を使用し、その後、person の名前に続けてbows politelyという additional line を Print します。main.lua: FormalPerson module を Require し、input から名前を読み取り、FormalPerson instance を Create して、:introduce()を Call し、両方の behavior が組み合わさった結果を確認します。
input は1つ、person の名前です。
FormalPerson に対して :introduce() を Call すると、Output は2行になります。1行目は parent の method によるもの、2行目は Child による追加です。
{name} says hi
{name} bows politelyたとえば、input が Eleanor の場合、Output は次のようになります。
Eleanor says hi
Eleanor bows politelyここでの重要なポイントは、FormalPerson が「says hi」のロジックを重複させていないことです。その処理を parent の method に委ねた後、自身の固有の behavior を上に追加しています。これによりコードがすっきりし、Child class が parent の機能を置き換えるのではなく拡張できることが分かります。
自分で試してみよう
-- main.lua: 挨拶システムのエントリーポイント
local FormalPerson = require('FormalPerson')
-- 入力から人物の名前を読み取る
local name = io.read()
-- TODO: 指定された名前でFormalPersonのインスタンスを作成する
-- TODO: FormalPersonインスタンスのintroduceメソッドを呼び出す
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
自分で練習してみよう: Luaオンラインコンパイラ