Menu
Coddy logo textTech

프라이버시를 위한 클로저

Coddy Lua 여정의 객체 지향 프로그래밍 (Object Oriented Programming) 섹션에 포함된 레슨. 70개 중 44번째.

명명 규칙은 의도를 나타내지만 실제로 접근을 방지하지는 않습니다. 누구나 여전히 player._health = 999라고 작성할 수 있으며, 이 코드는 작동합니다. 진정한 privacy를 위해 Lua는 다른 접근 방식을 제공합니다. 데이터를 self에 저장하는 대신 생성자 내부의 local 변수에 저장하는 것입니다.

핵심 통찰은 함수 내부의 local 변수는 해당 function과 그 안에 정의된 모든 function 내부에서만 접근할 수 있다는 것입니다. 이를 closure라고 합니다:

local Counter = {}
Counter.__index = Counter

function Counter:new()
    local count = 0  -- 진정으로 private! self에 없음.
    
    local obj = {}
    setmetatable(obj, Counter)
    return obj
end

이 예제에서 count:new() 함수 내부에만 존재합니다. 이는 obj에 저장되지 않으므로 외부에서 접근할 방법이 없습니다. myCounter.countnil을 반환하며, 이를 우회할 밑줄 접두사 필드도 없습니다.

변수 count는 클로저의 스코프에 존재합니다. 이 변수는 외부 코드에서 완전히 숨겨진 상태로 유지됩니다. (현재 작성된 내용에서는 아직 어떤 것도 count를 캡처하지 않습니다. 다음 레슨에서는 생성자 내부에 count를 캡처하는 메서드를 추가하여 객체가 존재하는 동안 계속 유지되도록 할 것입니다.) 단순한 정중한 제안에 불과한 self._count와 달리, 이 방식은 데이터를 실제로 접근할 수 없게 만듭니다.

물론 숨겨진 data는 절대 상호작용할 수 없다면 유용하지 않습니다. 다음 수업에서는 생성자 내부에 메서드를 정의하여 이러한 private 변수를 read하고 수정하는 방법을 배우게 됩니다. 이를 통해 진정한 캡슐화를 유지하면서도 제어된 액세스 권한을 제공할 수 있습니다.

challenge icon

챌린지

쉬움

진정한 데이터 privacy를 closures를 사용하여 보여주는 SecretKeeper class를 만들어 봅시다! 이전 lesson의 underscore 규칙과 달리, 이 접근 방식은 object 외부에서 데이터에 실제로 접근할 수 없게 만듭니다.

코드를 두 개의 파일로 구성합니다:

  • SecretKeeper.lua: secret이 self에 저장되지 않고 constructor 내부의 local variable에 저장되는 class를 만드세요. constructor :new(secretValue)는 closure 내부에만 존재하는 local variable에 secret을 저장해야 합니다. 현재는 object가 이 secret에 접근할 방법이 없습니다(다음 lesson에서 다룹니다!). 하지만 object가 제대로 작동하는지 확인할 수 있도록 instance에 public name field를 "Keeper"로 설정하여 저장해야 합니다.
  • main.lua: SecretKeeper module을 Require하고 input에서 secret 값을 read하세요. 해당 secret으로 SecretKeeper instance를 Create하세요. 그런 다음 다음 세 가지를 Print하여 secret이 truly private임을 보여 주세요:
    • keeper의 name field (Keeper를 Print해야 함)
    • keeper.secret에 access하려고 하면 happens하는 일 (nil이어야 함)
    • keeper._secret에 access하려고 하면 happens하는 일 (역시 nil이어야 함)

하나의 input을 받습니다:

  1. 저장할 secret 값 (예: TopSecret123)

output은 public field가 작동하는 반면 secret은 완전히 숨겨져 있음을 보여 주는 세 줄이어야 합니다:

Name: Keeper
secret: nil
_secret: nil

어떤 secret을 input으로 전달하더라도 output은 동일합니다. secret에 access할 방법이 없기 때문입니다! constructor 내부의 local variable은 외부 세계에서 보이지 않습니다. 이는 closure 기반 privacy가 underscore naming convention과 fundamentally 다르다는 것을 증명합니다.

예를 들어 input이 MyPassword인 경우에도 output은 다음과 같아야 합니다:

Name: Keeper
secret: nil
_secret: nil
필수 output 형식: [번역된 콘텐츠]

직접 해보기

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

-- 입력에서 비밀 값을 읽습니다
local secretValue = io.read()

-- TODO: 비밀 값으로 SecretKeeper 인스턴스를 생성합니다

-- TODO: keeper의 name 필드를 출력합니다 (형식: "Name: <name>")

-- TODO: keeper.secret에 접근할 때 일어나는 일을 출력합니다 (형식: "secret: <value>")

-- TODO: keeper._secret에 접근할 때 일어나는 일을 출력합니다 (형식: "_secret: <value>")
quiz icon실력 점검

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

객체 지향 프로그래밍 (Object Oriented Programming)의 모든 레슨

직접 연습해 보세요: 온라인 Lua 컴파일러