پروتکل سازوکاری برای دستیابی به «چندریختی» در 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.Edible را برای آیتم RPG.LoafOfBread پیادهسازی کنید. وقتی خورده میشود، یک قرص نان ۵ امتیاز سلامتی به شخصیت میدهد و محصول جانبیای ندارد.
RPG.Edible.eat(%RPG.LoafOfBread{}, %RPG.Character{health: 31})
# => {nil, %RPG.Character{health: 36, mana: 0}}
پروتکل RPG.Edible را برای آیتم RPG.ManaPotion پیادهسازی کنید. وقتی خورده میشود، یک معجون مانا به اندازهی قدرت معجون به شخصیت امتیاز مانا میدهد و یک بطری خالی تولید میکند.
RPG.Edible.eat(%RPG.ManaPotion{strength: 13}, %RPG.Character{mana: 50})
# => {%RPG.EmptyBottle{}, %RPG.Character{health: 100, mana: 63}}
پروتکل RPG.Edible را برای آیتم RPG.Poison پیادهسازی کنید. وقتی خورده میشود، سم همهی امتیازهای سلامتی را از شخصیت میگیرد و یک بطری خالی تولید میکند.
RPG.Edible.eat(%RPG.Poison{}, %RPG.Character{health: 3000})
# => {%RPG.EmptyBottle{}, %RPG.Character{health: 0, mana: 0}}