덕 타이핑
Coddy Lua 여정의 객체 지향 프로그래밍 (Object Oriented Programming) 섹션에 포함된 레슨. 70개 중 39번째.
Lua는 객체의 class를 신경 쓰지 않습니다. 객체가 무엇을 할 수 있는지만 신경 씁니다. 이 개념을 duck typing이라고 합니다. "duck처럼 걷고 duck처럼 꽥꽥거리면, 그것은 duck입니다." 프로그래밍 용어로 말하면, 객체에 호출하려는 method가 있으면 작동합니다.
이는 완전히 관련 없는 class들도 동일한 method 이름을 공유하는 한 함께 사용할 수 있다는 뜻입니다:
local Circle = {}
Circle.__index = Circle
function Circle:new()
local obj = {}
setmetatable(obj, Circle)
return obj
end
function Circle:draw()
print("Drawing a circle")
end
local Square = {}
Square.__index = Square
function Square:new()
local obj = {}
setmetatable(obj, Square)
return obj
end
function Square:draw()
print("Drawing a square")
end이 classes에는 상속 관계가 없습니다. 서로 완전히 독립적입니다. 하지만 이들을 동일하게 다룰 수 있습니다:
local shapes = {Circle:new(), Square:new(), Circle:new()}
for _, shape in ipairs(shapes) do
shape:draw()
end
-- 출력:
-- 원 그리기
-- 사각형 그리기
-- 원 그리기이 loop는 각 객체가 어떤 유형인지 확인하지 않습니다. 단순히 :draw()를 호출하고 method가 존재한다고 신뢰합니다. 이러한 유연성은 강력합니다. loop 코드를 전혀 수정하지 않고도 새로운 도형 유형을 추가할 수 있습니다. 새로운 class가 :draw()를 구현하기만 하면 just 작동합니다.
챌린지
쉬움서로 완전히 관련 없는 class들을 같은 방식으로 모두 처리할 수 있는 notification 시스템을 만들어 duck typing의 강력함을 보여 줍시다!
서로 상속하지 않는 독립적인 notification class 세 개를 만들지만, 모두 :send() method를 구현합니다. 따라서 실제 유형을 신경 쓰지 않고 혼합된 컬렉션을 순회하며 각 항목에 :send()를 call할 수 있습니다.
코드를 네 개의 파일로 구성합니다:
Email.lua: 이메일을 받을 사람을 저장하는:new(recipient)constructor가 있는 class입니다. 이 class의:send()method는Emailing {recipient}을 출력해야 합니다.SMS.lua::new(phoneNumber)constructor가 있는 완전히 별개의 class입니다. 이 class의:send()method는Texting {phoneNumber}를 출력해야 합니다.PushNotification.lua::new(deviceId)constructor가 있는 또 다른 독립적인 class입니다. 이 class의:send()method는Pushing to {deviceId}를 출력해야 합니다.main.lua: 모든 것을 함께 구성합니다! 세 개의 입력을 읽고, 각 notification 유형의 instance를 하나씩 만들고, 모두 하나의 테이블에 넣은 다음, 테이블을 순회하며 각 항목에:send()를 call합니다.
세 개의 입력을 받습니다:
- 이메일 수신자 (예:
alice@example.com) - 전화번호 (예:
555-1234) - device ID (예:
device_99)
main 파일에서 세 notification 객체를 모두 만들고, 테이블에 저장한 다음, 테이블을 순회하며 각 객체에 :send()를 call합니다. 순서는 Email first, then SMS, then PushNotification이어야 합니다.
예를 들어 입력이 bob@mail.com, 555-9876, phone_42인 경우 출력은 다음과 같아야 합니다:
Emailing bob@mail.com
Texting 555-9876
Pushing to phone_42Loop에서 각 객체가 어떤 유형인지 확인할 필요가 없다는 점에 주목하세요. 컬렉션의 모든 객체가 :send() method를 가지고 있다고 믿고 그대로 call할 뿐입니다. 이것이 바로 duck typing의 실제 동작입니다! :send()할 수 있다면 notification입니다.
직접 해보기
-- main.lua
-- 모든 알림 유형을 한데 모으고 덕 타이핑을 시연합니다
-- 알림 클래스들을 가져옵니다
local Email = require('Email')
local SMS = require('SMS')
local PushNotification = require('PushNotification')
-- 입력을 읽습니다
local recipient = io.read()
local phoneNumber = io.read()
local deviceId = io.read()
-- TODO: 각 알림 유형의 인스턴스를 하나씩 생성합니다
-- TODO: 모든 알림을 하나의 테이블에 넣습니다 (Email 먼저, 그다음 SMS, 그다음 PushNotification)
-- TODO: 테이블을 순회하며 각 알림에 :send()를 호출합니다
-- 이것은 덕 타이핑을 보여줍니다 - 타입을 확인하지 않고 그냥 :send()를 호출합니다
이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.
객체 지향 프로그래밍 (Object Oriented Programming)의 모든 레슨
직접 연습해 보세요: 온라인 Lua 컴파일러