메서드 오버라이딩
Coddy Lua 여정의 Object Oriented Programming 섹션에 포함된 레슨 — 70개 중 37번째.
지금까지 자식 클래스는 부모 메서드를 상속받고 새로운 메서드를 추가해 왔습니다. 하지만 자식이 동일한 메서드 이름을 가지면서 다른 동작을 수행해야 한다면 어떻게 해야 할까요? 이것을 메서드 오버라이딩(method overriding)이라고 합니다.
자식 클래스에서 부모 클래스와 동일한 이름의 메서드를 정의하면, 자식 클래스의 버전이 우선순위를 갖습니다. Lua의 조회 체인(lookup chain)은 자식 클래스를 먼저 확인하며, 거기서 메서드를 찾으면 조회를 중단합니다.
local Animal = {}
Animal.__index = Animal
function Animal:new(name)
local obj = {name = name}
setmetatable(obj, Animal)
return obj
end
function Animal:speak()
print(self.name .. " makes a sound")
end
-- Dog가 speak()를 재정의합니다
local Dog = {}
Dog.__index = Dog
setmetatable(Dog, {__index = Animal})
function Dog:new(name)
local obj = Animal.new(Animal, name)
setmetatable(obj, Dog)
return obj
end
function Dog:speak()
print(self.name .. " barks: Woof!")
end이제 각 클래스는 동일한 메서드 호출에 대해 서로 다르게 반응합니다:
local generic = Animal:new("Creature")
local buddy = Dog:new("Buddy")
generic:speak() -- 출력: Creature makes a sound
buddy:speak() -- 출력: Buddy barks: Woof!Dog의 :speak()는 Dog 인스턴스에 대해 부모의 버전을 완전히 대체합니다. 이를 통해 일관된 인터페이스를 유지하면서도 특화된 동작을 만들 수 있습니다. 모든 동물은 :speak()를 할 수 있지만, 각 종마다 다르게 수행합니다.
챌린지
쉬움서로 다른 생물들이 각자의 독특한 방식으로 말하는 작은 동물 왕국을 만들어 봅시다! Animal 부모 클래스와 두 개의 자식 클래스인 Cat 및 Cow를 생성하고, 각 자식 클래스에서 부모의 :speak() 메서드를 고유한 동작으로 오버라이드하게 됩니다.
코드는 다음 네 개의 파일로 구성됩니다:
Animal.lua: 동물의 이름을 저장하는:new(name)생성자를 가진 기본 클래스입니다. 동물의 이름 뒤에makes a sound를 출력하는:speak()메서드를 포함하세요. 이것은 자식 클래스들이 오버라이드할 기본 동작입니다.Cat.lua: Animal을 상속받는 자식 클래스입니다.:new(name)생성자는 부모 생성자를 호출한 다음, 메타테이블을 Cat으로 다시 연결해야 합니다. 고양이가 다르게 말하도록:speak()메서드를 오버라이드하세요. 고양이 이름 뒤에meows: Meow!를 출력합니다.Cow.lua: Animal을 상속받는 또 다른 자식 클래스입니다. Cat과 동일한 방식으로 생성자를 설정하세요. 소가 이름 뒤에moos: Moo!를 출력하도록:speak()를 오버라이드하세요.main.lua: 모든 것을 하나로 합칩니다! 입력에서 두 개의 이름을 읽어 첫 번째 이름으로 Cat을, 두 번째 이름으로 Cow를 생성한 다음, 각각에 대해:speak()를 호출하여 동일한 메서드 이름이 클래스에 따라 다른 출력을 생성함을 보여주세요.
두 개의 입력을 받게 됩니다:
- 고양이 이름
- 소 이름
메인 파일에서 두 동물을 모두 생성하고 고양이에게 먼저 :speak()를 호출한 다음, 소에게 호출하세요.
예를 들어, 입력이 Whiskers와 Bessie라면 출력은 다음과 같아야 합니다:
Whiskers meows: Meow!
Bessie moos: Moo!두 동물 모두 동일한 :speak() 메서드 호출에 응답하지만, 각자 자신의 타입에 특화된 출력을 생성하는 방식에 주목하세요. Cat의 버전은 부모의 일반적인 "makes a sound" 동작을 완전히 대체하며, Cow의 버전도 마찬가지입니다. 이것이 바로 메서드 오버라이딩(method overriding)의 실제 사례입니다 — 동일한 인터페이스, 서로 다른 구현!
치트 시트
메서드 오버라이딩(Method overriding)을 사용하면 자식 클래스가 부모 메서드와 동일한 이름의 메서드를 정의하여, 부모의 동작을 특화된 기능으로 대체할 수 있습니다.
Lua가 메서드를 찾을 때, 먼저 자식 클래스를 확인합니다. 거기서 메서드를 찾으면 해당 버전을 사용하고 부모 클래스 검색을 중단합니다.
메서드 오버라이딩의 기본 예시:
local Animal = {}
Animal.__index = Animal
function Animal:new(name)
local obj = {name = name}
setmetatable(obj, Animal)
return obj
end
function Animal:speak()
print(self.name .. " makes a sound")
end
-- Dog overrides speak()
local Dog = {}
Dog.__index = Dog
setmetatable(Dog, {__index = Animal})
function Dog:new(name)
local obj = Animal.new(Animal, name)
setmetatable(obj, Dog)
return obj
end
function Dog:speak()
print(self.name .. " barks: Woof!")
end오버라이드된 메서드 사용하기:
local generic = Animal:new("Creature")
local buddy = Dog:new("Buddy")
generic:speak() -- Output: Creature makes a sound
buddy:speak() -- Output: Buddy barks: Woof!자식 클래스의 메서드는 해당 자식 클래스의 인스턴스에 대해 부모의 버전을 완전히 대체하여, 모든 클래스에서 일관된 인터페이스를 유지하면서도 특화된 동작을 가능하게 합니다.
직접 해보기
-- main.lua: 모든 것을 하나로 합치기
local Cat = require('Cat')
local Cow = require('Cow')
-- 입력 읽기
local catName = io.read()
local cowName = io.read()
-- TODO: 첫 번째 이름으로 Cat 생성하기
-- TODO: 두 번째 이름으로 Cow 생성하기
-- TODO: 먼저 cat에서 :speak()를 호출한 다음, cow에서 호출하기
이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.