Menu
Coddy logo textTech

공통 인터페이스

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

덕 타이핑은 서로 관련 없는 class들이 method 이름을 공유하면 함께 작동할 수 있다는 것을 보여 주었습니다. 이 아이디어는 강력한 설계 개념인 공통 인터페이스로 이어집니다. 여러 class가 동일한 method 시그니처를 갖도록 의도적으로 설계하면, 서로 교체 가능한 구성 요소를 만들 수 있습니다.

로깅 시스템을 구축한다고 상상해 보세요. 메시지를 파일, 화면 또는 네트워크와 같은 다양한 대상으로 보내고 싶을 수 있습니다. 각각에 대해 별도의 코드를 작성하는 대신, 모든 output 클래스가 동일한 :write() method를 Implement하도록 설계합니다:

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 함수는 어떤 class를 전달받는지 알거나 신경 쓰지 않습니다. 단지 :write() method를 기대할 뿐입니다. 이로 인해 코드가 유연해집니다. 나중에 기존 function을 변경하지 않고도 새로운 output 유형을 추가할 수 있습니다.

challenge icon

챌린지

쉬움

서로 다른 결제 방법을 서로 바꿔 사용할 수 있는 결제 처리 시스템을 만들어 봅시다! 공통 인터페이스인 :process(amount) method를 공유하는, 서로 완전히 관련 없는 두 개의 결제 클래스를 만들 것입니다. 이를 통해 결제를 처리하는 모든 코드가 차이를 알지 못한 채 어느 유형과도 함께 작동할 수 있습니다.

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

  • CreditCard.lua: 카드 번호를 저장하는 :new(cardNumber) constructor를 가진 결제 클래스입니다. 이 클래스의 :process(amount) method는 Charging {amount} to card {cardNumber}를 출력해야 합니다.
  • BankTransfer.lua: 완전히 별개의 결제 클래스이며, :new(accountId) constructor를 가집니다. 이 클래스의 :process(amount) method는 Transferring {amount} from account {accountId}를 출력해야 합니다.
  • main.lua: handlePayment(paymentMethod, amount)라는 function을 만듭니다. 이 function은 모든 payment object와 금액을 받아들인 다음, 해당 object에서 :process(amount)를 호출합니다. 이 function은 신용 카드와 은행 이체 중 무엇을 처리하는지 알 필요가 없습니다. 단지 object에 :process() method가 있기를 기대합니다.

세 개의 입력을 받습니다:

  1. 신용 카드 번호(예: 4532-1234-5678)
  2. 은행 account ID(예: ACC-9876)
  3. 결제 금액(예: 150)

main 파일에서 처음 두 입력을 사용하여 각 결제 유형의 instance를 하나씩 만듭니다. 그런 다음 handlePayment function을 사용하여 주어진 금액을 두 payment method를 통해 처리합니다. 먼저 신용 카드로 처리한 다음 은행 이체로 처리합니다.

예를 들어 입력이 1111-2222-3333, ACC-5555, 75라면 출력은 다음과 같아야 합니다:

Charging 75 to card 1111-2222-3333
Transferring 75 from account ACC-5555

이 설계의 장점은 handlePayment function이 :process()를 Implement하는 모든 object와 함께 작동한다는 것입니다. 내일 PayPal 클래스를 추가하더라도 :process(amount) method만 가지고 있다면 기존 function을 변경하지 않고도 작동합니다!

직접 해보기

-- 결제 클래스 가져오기
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를 사용하여 두 결제 방법으로 금액 처리하기
-- 먼저 신용카드, 그다음 은행 이체
quiz icon실력 점검

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

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

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