공통 인터페이스
Coddy Lua 여정의 객체 지향 프로그래밍 (Object Oriented Programming) 섹션에 포함된 레슨 — 70개 중 40번째.
덕 타이핑(Duck typing)은 서로 관련 없는 클래스들이 메서드 이름을 공유할 경우 함께 작동할 수 있음을 보여주었습니다. 이 아이디어는 강력한 설계 개념인 공통 인터페이스(common interface)로 이어집니다. 여러 클래스가 동일한 메서드 시그니처를 갖도록 의도적으로 설계하면, 서로 교체 가능한 컴포넌트를 만들 수 있습니다.
로깅 시스템을 구축한다고 상상해 보세요. 메시지를 파일, 화면 또는 네트워크와 같은 다양한 대상으로 보내고 싶을 수 있습니다. 각각에 대해 별도의 코드를 작성하는 대신, 모든 출력 클래스가 동일한 :write() 메서드를 구현하도록 설계합니다:
local LogFile = {}
LogFile.__index = LogFile
function LogFile:new(filename)
local obj = {filename = filename}
setmetatable(obj, LogFile)
return obj
end
function LogFile:write(message)
print("[FILE:" .. self.filename .. "] " .. message)
end
local Screen = {}
Screen.__index = Screen
function Screen:new()
local obj = {}
setmetatable(obj, Screen)
return obj
end
function Screen:write(message)
print("[SCREEN] " .. message)
end이제 메시지를 출력해야 하는 모든 코드는 두 가지 유형 중 어느 것이든 수용할 수 있습니다:
local function logMessage(output, msg)
output:write(msg)
end
local file = LogFile:new("app.log")
local screen = Screen:new()
logMessage(file, "Starting up") -- [FILE:app.log] 시작 중
logMessage(screen, "Starting up") -- [SCREEN] 시작 중logMessage 함수는 어떤 클래스를 받는지 알 필요도 없고 신경 쓰지도 않습니다. 이 함수는 오직 :write() 메서드만 기대합니다. 이를 통해 코드가 유연해집니다. 기존 함수를 수정하지 않고도 나중에 새로운 출력 유형을 추가할 수 있습니다.
챌린지
쉬움서로 다른 결제 수단을 상호 교환하여 사용할 수 있는 결제 처리 시스템을 구축해 봅시다! 공통 인터페이스인 :process(amount) 메서드를 공유하는 완전히 별개의 두 결제 클래스를 만들게 됩니다. 이를 통해 결제를 처리하는 모든 코드는 차이점을 알 필요 없이 두 유형 중 어느 것과도 작동할 수 있습니다.
코드는 다음 세 개의 파일로 구성됩니다:
CreditCard.lua: 카드 번호를 저장하는:new(cardNumber)생성자가 있는 결제 클래스입니다. 이 클래스의:process(amount)메서드는Charging {amount} to card {cardNumber}를 출력해야 합니다.BankTransfer.lua::new(accountId)생성자가 있는 완전히 별개의 결제 클래스입니다. 이 클래스의:process(amount)메서드는Transferring {amount} from account {accountId}를 출력해야 합니다.main.lua: 임의의 결제 객체와 금액을 인자로 받아 해당 객체의:process(amount)를 호출하는handlePayment(paymentMethod, amount)함수를 만듭니다. 이 함수는 신용카드인지 은행 송금인지 알 필요가 없으며, 단지 객체에:process()메서드가 있을 것만 기대합니다.
세 가지 입력을 받게 됩니다:
- 신용카드 번호 (예:
4532-1234-5678) - 은행 계좌 ID (예:
ACC-9876) - 결제 금액 (예:
150)
메인 파일에서 처음 두 입력을 사용하여 각 결제 유형의 인스턴스를 하나씩 생성하세요. 그런 다음 handlePayment 함수를 사용하여 주어진 금액을 두 결제 수단(먼저 신용카드, 그다음 은행 송금)을 통해 처리하세요.
예를 들어, 입력이 1111-2222-3333, ACC-5555, 75인 경우 출력은 다음과 같아야 합니다:
Charging 75 to card 1111-2222-3333
Transferring 75 from account ACC-5555이 디자인의 장점은 handlePayment 함수가 :process()를 구현하는 모든 객체와 함께 작동한다는 것입니다. 내일 PayPal 클래스를 추가하더라도 :process(amount) 메서드만 있다면 기존 함수를 수정하지 않고도 그대로 사용할 수 있습니다!
직접 해보기
-- 결제 클래스 가져오기
local CreditCard = require('CreditCard')
local BankTransfer = require('BankTransfer')
-- 입력 읽기
local cardNumber = io.read()
local accountId = io.read()
local amount = tonumber(io.read())
-- TODO: 모든 결제 객체와 금액을 인자로 받는 handlePayment 함수를 생성하고,
-- 해당 객체에서 :process(amount)를 호출하도록 하세요
-- TODO: 입력을 사용하여 CreditCard 및 BankTransfer의 인스턴스를 생성하세요
-- TODO: handlePayment를 사용하여 두 결제 수단 모두를 통해 금액을 처리하세요
-- 먼저 신용카드, 그 다음 은행 송금 순으로 처리합니다
이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.