クロージャを介したアクセス
CoddyのLuaジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 45/70。
Private local variables は、それらと決してやり取りできないのであれば役に立ちません。解決策は、closure のスコープにアクセスできる constructor の内部で getter および setter methods を定義することです。
これらのmethodsは:new()の内部で作成されるため、local variablesを「見る」ことができます。それらをobjectにdirectly割り当てます:
local Counter = {}
Counter.__index = Counter
function Counter:new()
local count = 0 -- プライベート変数
local obj = {}
-- コンストラクタ内でメソッドを定義する
function obj:getCount()
return count
end
function obj:increment()
count = count + 1
end
setmetatable(obj, Counter)
return obj
endこれで、プライベートな count 変数にアクセスできますが、アクセスできるのはあなたが提供するメソッドを通じてのみです。
local c = Counter:new()
print(c:getCount()) -- 0
c:increment()
c:increment()
print(c:getCount()) -- 2
print(c.count) -- nil(まだ隠されている!):getCount()と:increment()はクラステーブルではなく、obj上に直接定義されていることに注意してください。各instanceはこれらの関数を独自にコピーして持ち、それぞれが自身のprivateなcountにアクセスできます。これがトレードオフです。真のプライバシーには少し多くのメモリが必要になります。これは、methodsがプロトタイプを通じて共有されないためです。
チャレンジ
簡単Celsius で温度値を保存するために closure-based privacy を使用し、制御されたアクセスを提供する getter と setter methods を constructor 内で定義する Temperature class を作成しましょう!
コードを 2 つのファイルに分けて整理します。
Temperature.lua:温度値を constructor 内の local variable に保存する class を作成します。外部からのアクセスから完全に hidden になります。constructor:new(initialCelsius)は温度を local variable に保存し、その後、次の methods を直接 object instance 上に Define します。:getCelsius():現在の温度を Celsius で返します:setCelsius(value):温度を新しい値に更新します:getFahrenheit():次の Formula を使用して、温度を Fahrenheit に converted して返します:(celsius * 9/5) + 32
main.lua:Temperature module を Require し、input から 2 つの値、つまり initial temperature と設定する new temperature を read します。initial value で Temperature instance を Create し、Celsius と Fahrenheit の readings を Print します。その後 setter を使用して温度を change し、両方の readings をもう一度 Print します。
次の 2 つの input を受け取ります。
- Celsius での initial temperature(数値)
- 設定する new temperature(数値)
output は、change 前後の temperature readings を示す 4 行にしてください。
Celsius: {initialValue}
Fahrenheit: {convertedInitial}
Celsius: {newValue}
Fahrenheit: {convertedNew}たとえば、input が 0 と 100 の場合、output は次のようになります。
Celsius: 0
Fahrenheit: 32
Celsius: 100
Fahrenheit: 212temperature value は :new() 内の local variable に保存し、self 上には保存しないでください。getter と setter methods は constructor 内で Define され、closure を通じてこの private variable にアクセスできます。temp.celsius または temp._celsius に直接アクセスしようとすると、nil が返されるはずです。
自分で試してみよう
-- Temperatureモジュールを読み込む
local Temperature = require('Temperature')
-- 入力値を読み取る
local initialTemp = tonumber(io.read())
local newTemp = tonumber(io.read())
-- TODO: 初期値でTemperatureインスタンスを作成する
-- TODO: 初期の摂氏と華氏の測定値を出力する
-- TODO: セッターを使って温度をnewTempに変更する
-- TODO: 更新後の摂氏と華氏の測定値を出力する
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
自分で練習してみよう: Luaオンラインコンパイラ