Menu
CoddyTech

믹스인 vs 상속

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

동작을 공유하는 두 가지 방법을 배웠습니다. 상속은 프로토타입 체인을 통해 "is-a" 관계를 만들고, 믹스인은 함수를 클래스에 직접 복사합니다. 하지만 각각의 방법은 언제 사용해야 할까요?

객체들이 근본적인 정체성을 공유할 때 상속을 사용하세요. Bird는 Animal의 한 종류입니다. Bird가 :eat()이나 :sleep() 같은 동물의 핵심 동작을 상속하는 것은 타당합니다. 이 관계는 영구적이며 객체의 근본적인 정체성을 정의합니다.

객체의 핵심 정체성을 정의하지 않는 기능을 추가하고 싶을 때는 믹스인을 사용하세요.

모든 새가 날 수 있는 것은 아닙니다. 펭귄과 타조는 새이지만 날지 못합니다. 나는 것은 새의 능력이지, 새를 규정하는 특성이 아닙니다. Flyable 믹스인을 사용하면 모든 새에게 비행 능력을 강요하지 않고, 필요한 새에게 비행 능력을 추가할 수 있습니다.

두 접근 방식은 함께 작동합니다. 여기서 Eagle과 Penguin은 모두 Bird를 상속하고, Eagle만 믹스인을 받습니다.

-- Bird는 Animal을 상속받습니다(is-a 관계)
local Bird = {}
Bird.__index = Bird
setmetatable(Bird, {__index = Animal})

-- Eagle과 Penguin은 둘 다 새입니다
local Eagle = setmetatable({}, {__index = Bird})
Eagle.__index = Eagle
local Penguin = setmetatable({}, {__index = Bird})
Penguin.__index = Penguin

-- Flyable은 기능입니다(믹스인)
local Flyable = {}
function Flyable:fly()
    print(self.name .. " soars through the sky!")
end

-- 믹스인은 날 수 있는 새에만 적용합니다
applyMixin(Eagle, Flyable)

독수리는 :fly()를 호출할 수 있습니다. 펭귄은 호출할 수 없습니다. fly는 Penguin, Bird 또는 Animal에 없으므로 penguin:fly()는 오류입니다. 대신 믹스인을 Bird에 적용하면 모든 새에게, 펭귄을 포함해 fly가 복사됩니다.

challenge icon

챌린지

쉬움

상속과 믹스인 중 언제 무엇을 사용해야 하는지 보여 주는 작은 생태계를 만들어 봅시다! Animal 기본 클래스를 만들고, 이를 상속하는 Bird와 Swimmable 믹스인을 만들 거예요. 모든 새가 동물이기는 하지만, 모든 새가 수영할 수 있는 것은 아니기 때문입니다.

코드를 네 개의 파일로 나누어 작성하세요:

  • Animal.lua: 생성자 :new(name)를 통해 이름을 저장하는 기본 Animal 클래스를 만드세요. {name} is eating을 출력하는 :eat() 메서드도 포함하세요. 이는 모든 동물이 공유하는 핵심 정체성을 나타냅니다.
  • Swimmable.lua: {self.name} is swimming을 출력하는 :swim() 메서드가 있는 믹스인을 만드세요. 이는 능력입니다. 모든 생물이 수영할 수 있는 것은 아니므로, 상속 계층에 포함하면 안 됩니다.
  • Bird.lua: Animal을 상속하는 Bird 클래스를 만드세요. 생성자 :new(name)은 부모 생성자를 호출해야 합니다. {name} chirps!를 출력하는 :chirp() 메서드를 포함하세요. 이는 새에게만 해당하는 동작입니다. 수영 기능은 Bird에 넣지 마세요. 모든 새가 수영할 수 있는 것은 아닙니다.
  • main.lua: 여기에서 믹스인의 모든 함수를 대상에 복사하는 applyMixin(target, mixin) 헬퍼를 작성하세요. 새의 이름과 수영할 수 있는지 여부(yes 또는 no)를 읽으세요. Bird를 만들고, 수영할 수 있다면 해당 새에만 Swimmable 믹스인을 적용하세요. 그런 다음 :eat()(Animal에서 상속됨)과 :chirp()(Bird 고유 메서드)를 호출하고, 이 새에게 해당 메서드가 있는 경우에만 :swim()을 호출하세요(if bird.swim then).

입력은 두 개입니다:

  1. 새의 이름(문자열)
  2. 새가 수영할 수 있는지 여부: yes 또는 no

새가 수영할 수 있다면 출력은 다음과 같아야 합니다:

{name} is eating
{name} chirps!
{name} is swimming

새가 수영할 수 없다면 출력은 다음과 같아야 합니다:

{name} is eating
{name} chirps!

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

Duck is eating
Duck chirps!
Duck is swimming

입력이 Sparrow와 no라면 출력은 다음과 같아야 합니다:

Sparrow is eating
Sparrow chirps!

이 과제는 핵심적인 차이를 보여 줍니다. Bird는 Animal의 일종이므로 상속을 사용하지만, 수영은 선택적인 능력이므로 믹스인을 사용합니다. 믹스인은 수영할 수 있는 새에만 적용되므로, 수영할 수 없는 새에는 swim 메서드 자체가 없습니다.

직접 해보기

-- main.lua: 진입점 - 새를 생성하고 새의 능력을 보여주기

-- 클래스나 단일 객체에 믹스인을 적용하는 도우미 함수
local function applyMixin(target, mixin)
    -- TODO: mixin의 모든 함수를 target에 복사하기

end

local Bird = require('Bird')
local Swimmable = require('Swimmable')

-- 입력 읽기
local name = io.read()
local canSwimInput = io.read()

-- TODO: name으로 Bird 인스턴스 생성하기

-- TODO: 입력이 "yes"이면 이 새에만 Swimmable 믹스인 적용하기

-- TODO: Animal에서 상속받은 eat() 호출하기

-- TODO: Bird 자체 메서드인 chirp() 호출하기

-- TODO: 이 새에 swim()이 있을 때만 호출하기
quiz icon실력 점검

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

객체 지향 프로그래밍의 모든 레슨

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