Menu
Coddy logo textTech

클로저를 통한 접근

Coddy Lua 여정의 Object Oriented Programming 섹션에 포함된 레슨 — 70개 중 45번째.

비공개 지역 변수는 그것들과 상호작용할 수 없다면 아무런 소용이 없습니다. 해결책은 클로저의 스코프에 접근할 수 있는 생성자 내부에 게터(getter)와 세터(setter) 메서드를 정의하는 것입니다.

이러한 메서드들은 :new() 내부에서 생성되므로 지역 변수들을 "볼" 수 있습니다. 이들을 객체에 직접 할당합니다:

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에 직접 정의되어 있다는 점에 유의하세요. 각 인스턴스는 이 함수들의 개별 복사본을 갖게 되며, 각각 자신의 비공개 count에 접근할 수 있습니다. 이것이 트레이드오프(trade-off)입니다. 메서드가 프로토타입을 통해 공유되지 않기 때문에 진정한 프라이버시를 구현하려면 메모리가 조금 더 소모됩니다.

challenge icon

챌린지

쉬움

클로저 기반 프라이버시를 사용하여 섭씨 온도를 저장하고, 생성자 내부에 정의된 게터(getter) 및 세터(setter) 메서드를 통해 제어된 접근을 제공하는 Temperature 클래스를 만들어 봅시다!

코드는 다음 두 개의 파일로 구성됩니다:

  • Temperature.lua: 온도 값이 생성자 내부의 지역 변수에 저장되어 외부 접근으로부터 완전히 숨겨진 클래스를 생성합니다. 생성자 :new(initialCelsius)는 온도를 지역 변수에 저장한 다음, 객체 인스턴스에 직접 다음 메서드들을 정의해야 합니다:
    • :getCelsius() — 현재 섭씨 온도를 반환합니다.
    • :setCelsius(value) — 온도를 새로운 값으로 업데이트합니다.
    • :getFahrenheit()(celsius * 9/5) + 32 공식을 사용하여 섭씨 온도를 화씨로 변환하여 반환합니다.
  • main.lua: Temperature 모듈을 불러오고(require) 입력으로부터 두 개의 값(초기 온도와 새로 설정할 온도)을 읽습니다. 초기 값으로 Temperature 인스턴스를 생성하고, 섭씨 및 화씨 온도를 출력한 다음, 세터를 사용하여 온도를 변경하고 두 온도를 다시 출력합니다.

두 개의 입력을 받게 됩니다:

  1. 초기 섭씨 온도 (숫자)
  2. 새로 설정할 온도 (숫자)

출력은 변경 전과 후의 온도 수치를 보여주는 네 줄이어야 합니다:

Celsius: {initialValue}
Fahrenheit: {convertedInitial}
Celsius: {newValue}
Fahrenheit: {convertedNew}

예를 들어, 입력이 0100이라면 출력은 다음과 같아야 합니다:

Celsius: 0
Fahrenheit: 32
Celsius: 100
Fahrenheit: 212

주의: 온도 값은 self가 아닌 :new() 내부의 지역 변수에 저장되어야 합니다. 게터와 세터 메서드는 클로저를 통해 이 프라이빗 변수에 접근할 수 있도록 생성자 내부에서 정의됩니다. temp.celsius 또는 temp._celsius에 직접 접근하려고 하면 nil이 반환되어야 합니다!

치트 시트

Lua 클래스에서 진정한 프라이빗 변수를 생성하려면, 클로저를 통해 지역 변수에 접근할 수 있는 생성자 내부에 getter와 setter 메서드를 정의하세요.

메서드는 클래스 테이블이 아닌 객체 인스턴스에 직접 할당되어, 각 인스턴스가 자체 프라이빗 변수에 접근할 수 있는 고유한 복사본을 갖게 됩니다:

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

사용법:

local c = Counter:new()
print(c:getCount())  -- 0
c:increment()
c:increment()
print(c:getCount())  -- 2
print(c.count)       -- nil (여전히 숨겨져 있음!)

트레이드오프: 각 인스턴스는 메서드의 자체 복사본을 갖게 되며(프로토타입을 통해 공유되지 않음), 이는 더 많은 메모리를 사용하지만 진정한 프라이버시를 제공합니다.

직접 해보기

-- Temperature 모듈을 불러옵니다
local Temperature = require('Temperature')

-- 입력 값을 읽습니다
local initialTemp = tonumber(io.read())
local newTemp = tonumber(io.read())

-- TODO: 초기 값으로 Temperature 인스턴스를 생성합니다

-- TODO: 초기 섭씨 및 화씨 온도를 출력합니다

-- TODO: setter를 사용하여 온도를 newTemp로 변경합니다

-- TODO: 업데이트된 섭씨 및 화씨 온도를 출력합니다
quiz icon실력 점검

이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.

Object Oriented Programming의 모든 레슨