믹스인 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가 복사됩니다.
챌린지
쉬움상속과 믹스인 중 언제 무엇을 사용해야 하는지 보여 주는 작은 생태계를 만들어 봅시다! 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).
입력은 두 개입니다:
- 새의 이름(문자열)
- 새가 수영할 수 있는지 여부:
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()이 있을 때만 호출하기
이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.
객체 지향 프로그래밍의 모든 레슨
직접 연습해 보세요: 온라인 Lua 컴파일러