프로토콜은 데이터 타입에 따라 동작이 달라지길 원할 때 Elixir에서 다형성을 구현하는 방법이에요.
프로토콜은 defprotocol로 정의하고, 하나 이상의 함수 헤더를 담아요.
defprotocol Reversible do
def reverse(term)
end
프로토콜은 defimpl로 구현할 수 있어요.
defimpl Reversible, for: List do
def reverse(term) do
Enum.reverse(term)
end
end
프로토콜은 기존 Elixir 데이터 타입이나 구조체에 대해 구현할 수 있어요.
프로토콜 함수를 호출하면 첫 번째 인자의 타입에 따라 알맞은 구현이 자동으로 선택돼요.
직접 롤플레잉 비디오 게임을 만들고 있어요. 게임에는 _캐릭터_와 _아이템_이 있어요. 아이템으로 할 수 있는 여러 행동 중 하나는 캐릭터에게 아이템을 먹이는 거예요.
모든 아이템을 먹을 수 있는 건 아니고, 먹을 수 있는 아이템이라고 해서 모두 캐릭터에게 같은 효과를 주는 것도 아니에요. 어떤 아이템은 먹으면 다른 아이템으로 변하기도 해요. 예를 들어 사과를 먹으면 사과 꼭지가 남아요.
이런 유연성을 위해, 일부 아이템이 구현할 수 있는 Edible 프로토콜을 만들기로 했어요.
RPG.Edible 프로토콜을 만들어요. 이 프로토콜에는 eat이라는 함수가 하나 있어요. eat 함수는 아이템과 캐릭터를 받아서 부산물과 캐릭터를 반환해요.
RPG.LoafOfBread 아이템에 RPG.Edible 프로토콜을 구현해요. 빵을 먹으면 캐릭터의 체력이 5 포인트 늘어나고 부산물은 없어요.
RPG.Edible.eat(%RPG.LoafOfBread{}, %RPG.Character{health: 31})
# => {nil, %RPG.Character{health: 36, mana: 0}}
RPG.ManaPotion 아이템에 RPG.Edible 프로토콜을 구현해요. 마나 물약을 먹으면 물약의 strength만큼 캐릭터의 마나가 늘어나고, 빈 병이 생겨요.
RPG.Edible.eat(%RPG.ManaPotion{strength: 13}, %RPG.Character{mana: 50})
# => {%RPG.EmptyBottle{}, %RPG.Character{health: 100, mana: 63}}
RPG.Poison 아이템에 RPG.Edible 프로토콜을 구현해요. 독을 먹으면 캐릭터의 체력이 모두 사라지고, 빈 병이 생겨요.
RPG.Edible.eat(%RPG.Poison{}, %RPG.Character{health: 3000})
# => {%RPG.EmptyBottle{}, %RPG.Character{health: 0, mana: 0}}
Exercism에 가입하고 Elixir 트랙을 개념 58개연습 문제 168개, 그리고 실제 사람의 멘토링과 함께 배우고 익혀 보세요. 모두 무료예요.