Os protocolos são um mecanismo para alcançar polimorfismo em Elixir, quando queres que o comportamento varie consoante o tipo de dados.
Os protocolos definem-se com defprotocol e contêm um ou mais cabeçalhos de funções.
defprotocol Reversible do
def reverse(term)
end
Os protocolos podem ser implementados com defimpl.
defimpl Reversible, for: List do
def reverse(term) do
Enum.reverse(term)
end
end
Um protocolo pode ser implementado para qualquer tipo de dados existente do Elixir ou para uma struct.
Quando se invoca uma função de um protocolo, a implementação adequada é escolhida automaticamente com base no tipo do primeiro argumento.
Estás a desenvolver o teu próprio videojogo de interpretação de papéis. No teu jogo, existem personagens e itens. Uma das muitas ações que podes fazer com um item é fazer com que uma personagem o coma.
Nem todos os itens são comestíveis, e nem todos os itens comestíveis têm os mesmos efeitos na personagem. Alguns itens, quando comidos, transformam-se noutro item (por exemplo, se comeres uma maçã, ficas com o caroço da maçã).
Para permitir toda essa flexibilidade, decidiste criar um protocolo Edible que alguns dos itens podem implementar.
Cria o protocolo RPG.Edible. O protocolo tem uma função: eat. A função eat recebe um item e uma personagem e devolve um subproduto e uma personagem.
Implementa o protocolo RPG.Edible para o item RPG.LoafOfBread. Quando é comido, um pão dá à personagem 5 pontos de vida e não tem subproduto.
RPG.Edible.eat(%RPG.LoafOfBread{}, %RPG.Character{health: 31})
# => {nil, %RPG.Character{health: 36, mana: 0}}
Implementa o protocolo RPG.Edible para o item RPG.ManaPotion. Quando é comida, uma poção de mana dá à personagem tantos pontos de mana como a força da poção e produz um frasco vazio.
RPG.Edible.eat(%RPG.ManaPotion{strength: 13}, %RPG.Character{mana: 50})
# => {%RPG.EmptyBottle{}, %RPG.Character{health: 100, mana: 63}}
Implementa o protocolo RPG.Edible para o item RPG.Poison. Quando é comido, um veneno retira todos os pontos de vida à personagem e produz um frasco vazio.
RPG.Edible.eat(%RPG.Poison{}, %RPG.Character{health: 3000})
# => {%RPG.EmptyBottle{}, %RPG.Character{health: 0, mana: 0}}
Inscreve-te no Exercism para aprenderes e dominares Elixir com 58 conceitos168 exercícios, e mentoria humana real, tudo grátis.