Menu
CoddyTech

シンプルなミックスイン

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

コンポジションを使うと、オブジェクトをほかのオブジェクトの中に配置できます。しかし、関連のないクラス間で振る舞いを共有したい場合はどうすればよいでしょうか?

PlayerとMenuItemの両方に:describe()メソッドが必要かもしれませんが、共通の親クラスはありません。そこでミックスインの出番です。

ミックスインとは、関数を含むテーブルにすぎません。関数をコピーしてクラスに「混ぜ合わせ」ます。

local Printable = {}

function Printable:describe()
    print("Object: " .. tostring(self))
end

function Printable:log(message)
    print("[LOG] " .. message)
end

このミックスインをクラスに適用するには、ミックスインのテーブルから各関数をクラスのテーブルにコピーします。

local function applyMixin(class, mixin)
    for key, value in pairs(mixin) do
        class[key] = value
    end
end

local Player = {}
Player.__index = Player

applyMixin(Player, Printable)  -- これで Player は :describe() と :log() を持つ

ミックスインを適用すると、任意のPlayerインスタンスが、クラスに直接定義されているかのようにそれらのメソッドを呼び出せます。

local p = setmetatable({}, Player)
p:log("Player created")  -- [LOG] Player が作成されました

継承とは異なり、ミックスインは親子関係を作りません。あるテーブルから別のテーブルに関数をコピーしているだけです。

これにより、ミックスインは、ロギング、シリアル化、説明メソッドなど、ほかに共通点のないクラス間でユーティリティの動作を共有するのに最適です。

challenge icon

チャレンジ

簡単

ミックスインを使ってタグ付けシステムを作りましょう!どのクラスにも適用できるTaggableミックスインを作成し、オブジェクトがタグのコレクションを管理できるようにします。これは、アイテムや投稿など、ラベルが必要なあらゆるものの分類に役立ちます。

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

  • Taggable.lua:次の2つのメソッドを含むミックスインテーブルを作成します。
    • :addTag(tag):self.tagsにタグを追加します(テーブルが存在することを前提とします)
    • :listTags():すべてのタグをTags: tag1, tag2, tag3の形式で出力します(空の場合はTags: none)
  • Article.lua:タイトルを保存し、空のtagsテーブルを初期化するコンストラクター:new(title)を持つArticleクラスを作成します。記事のタイトルを返す:getTitle()メソッドも含めます。
  • main.lua:ここにヘルパー関数applyMixinを書き、次にapplyMixin(Article, Taggable)でミックスインを適用して、Articleのインスタンスにタグ付け機能を持たせます。その後、記事のタイトルと2つのタグの入力を読み込みます。Articleを作成し、両方のタグを追加して、タイトルを出力し、すべてのタグを一覧表示します。

入力は3つです。

  1. 記事のタイトル(文字列)
  2. 追加する最初のタグ(文字列)
  3. 追加する2番目のタグ(文字列)

出力には、記事のタイトルに続けてタグを表示します。

Title: {title}
Tags: {tag1}, {tag2}

たとえば、入力がLua Basics、programming、tutorialの場合、出力は次のようになります。

Title: Lua Basics
Tags: programming, tutorial

覚えておきましょう。ミックスインのメソッドが機能するのは、Articleのインスタンスに、ミックスインのメソッドが操作できるtagsテーブルがあるためです。このテーブルを作成するのはミックスインではありません。Articleのコンストラクターが作成します。ミックスインが提供するのは、共有される動作だけです!

自分で試してみよう

-- タグ付けシステムのメインファイル
local Taggable = require('Taggable')
local Article = require('Article')

-- TODO: applyMixin 関数を実装する
-- この関数は mixin テーブルから target テーブルにすべてのメソッドをコピーする
function applyMixin(target, mixin)
    -- TODO: mixin を走査し、各メソッドを target にコピーする
end

-- TODO: applyMixin を使って Taggable ミックスインを Article に適用する

-- 入力を読み取る
local title = io.read()
local tag1 = io.read()
local tag2 = io.read()

-- TODO: 指定されたタイトルで Article を作成する

-- TODO: 記事に両方のタグを追加する

-- TODO: タイトルを Title: {title} の形式で出力する

-- TODO: listTags メソッドを使ってすべてのタグを一覧表示する
quiz icon腕試し

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

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

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