独立したインスタンス
CoddyのLuaジャーニー「Object Oriented Programming」セクションの一部 — レッスン 10/70。
オブジェクト指向プログラミングの重要な側面は、各インスタンスが独自の独立した状態を保持することです。同じクラスから2つのオブジェクトを作成した場合、それらは完全に独立しており、一方を変更しても他方には影響しません。
この例を見てみましょう:
local Counter = {}
Counter.__index = Counter
function Counter:new(start)
local instance = {}
setmetatable(instance, self)
instance.value = start or 0
return instance
end
function Counter:increment()
self.value = self.value + 1
end
-- 2つの独立したカウンターを作成します
local counterA = Counter:new(10)
local counterB = Counter:new(5)
counterA:increment()
counterA:increment()
print(counterA.value) -- 出力: 12
print(counterB.value) -- 出力: 5両方のカウンターが同じ Counter クラスから生成されていても、counterA をインクリメントしても counterB には影響しません。各オブジェクトは、独自の value フィールドを持っており、それは自身のインスタンス・テーブルに格納されています。
この独立性こそが、オブジェクトを便利なものにしています。ゲーム内で数十人のプレイヤーを作成し、それぞれが自身の体力やスコアを追跡するようにできます。それぞれ異なる残高を持つ複数の銀行口座を管理することもできます。
クラスは構造と振る舞いを定義しますが、各インスタンスは独自のデータを持ち、それぞれ独立して存在します。
チャレンジ
簡単同じクラスから生成されたオブジェクトが、本当に独立して存在していることを証明しましょう!Walletクラスを作成し、2つの別々のウォレットインスタンスを生成します。そして、それらを個別に操作することで、一方への変更が他方に影響を与えないことを実証します。
コードは2つのファイルに分けて構成します:
Wallet.lua: 標準的なコンストラクタパターンを使用してWalletクラスを定義します。各ウォレットは独自のbalanceを保持する必要があります。以下を含めてください:- 指定された金額でウォレットを初期化する
:new(startingBalance)コンストラクタ - 残高を増やす
:add(amount)メソッド - 残高を減らす
:spend(amount)メソッド
- 指定された金額でウォレットを初期化する
main.lua: Walletモジュールを読み込み(require)、2つの別々のウォレットインスタンスを作成します。それぞれに対して異なる操作を行い、それらが独立した状態を維持していることを示します。
4つの入力を受け取ります:
- ウォレットAの開始残高
- ウォレットBの開始残高
- ウォレットAに追加する金額
- ウォレットBから支出する金額
メインファイル(main.lua)での手順:
- 1つ目の開始残高で
walletAを作成します - 2つ目の開始残高で
walletBを作成します - 指定された金額を
walletAに追加します - 指定された金額を
walletBから支出します - 両方の残高を別々の行に出力します
最終的な残高を以下の正確な形式で出力してください:
Wallet A: [balance]
Wallet B: [balance]例えば、入力が 100, 50, 25, 10 の場合、出力は以下のようになります:
Wallet A: 125
Wallet B: 40ウォレットAへの追加がウォレットBを変更せず、ウォレットBからの支出がウォレットAに影響を与えないこと、つまり各インスタンスが独自の個別の残高を維持していることに注目してください。
チートシート
クラスの各インスタンスは、それぞれ独自の独立した状態を保持します。同じクラスから複数のオブジェクトを作成すると、完全に独立したインスタンスが生成されます。一方を変更しても、他方には影響しません。
インスタンスの独立性を示す例:
local Counter = {}
Counter.__index = Counter
function Counter:new(start)
local instance = {}
setmetatable(instance, self)
instance.value = start or 0
return instance
end
function Counter:increment()
self.value = self.value + 1
end
-- 2つの独立したカウンターを作成
local counterA = Counter:new(10)
local counterB = Counter:new(5)
counterA:increment()
counterA:increment()
print(counterA.value) -- 出力: 12
print(counterB.value) -- 出力: 5各オブジェクトは、独自のデータを格納する独自のインスタンス・テーブルを持っています。クラスは構造と動作を定義しますが、各インスタンスは独立した状態を維持します。
自分で試してみよう
-- Walletモジュールを読み込む
local Wallet = require('Wallet')
-- 入力を読み込む
local startingA = tonumber(io.read())
local startingB = tonumber(io.read())
local addAmount = tonumber(io.read())
local spendAmount = tonumber(io.read())
-- TODO: 最初の開始残高でwalletAを作成する
-- TODO: 2番目の開始残高でwalletBを作成する
-- TODO: 指定された金額をwalletAに追加する
-- TODO: 指定された金額をwalletBから消費する
-- TODO: 最終的な残高を指定された形式で出力する
-- 形式: "Wallet A: [balance]" および "Wallet B: [balance]"
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。