رف

رفتار در Elixir

1 تمرین

درباره‌ی رفتار

رفتارها به ما امکان می‌دهند که رابط‌ها (مجموعه‌هایی از توابع و ماکروها) را در یک ماژول رفتار تعریف کنیم که بعداً می‌توانند توسط ماژول‌های کالبک مختلف پیاده‌سازی شوند. به لطف رابط مشترک، این ماژول‌های کالبک را می‌توان به‌جای یکدیگر به کار برد.

Note

به املای بریتانیایی «behaviours» توجه کنید.

تعریف رفتارها

برای تعریف یک رفتار، باید یک ماژول جدید بسازیم و فهرستی از توابعی را مشخص کنیم که بخشی از رابط موردنظر هستند. هر تابع باید با استفاده از ویژگی ماژول @callback تعریف شود. نحوه‌ی نگارش آن دقیقاً مثل مشخصات نوع تابع (@spec) است. باید اسم تابع، فهرستی از انواع آرگومان‌ها و همه‌ی انواع بازگشتی ممکن را مشخص کنیم.

defmodule Countable do
  @callback count(collection :: any) :: pos_integer
end

پیاده‌سازی رفتارها

برای افزودن یک رفتار موجود به ماژولمان (ساختن یک ماژول کالبک) از ویژگی ماژول @behaviour استفاده می‌کنیم. مقدار آن باید اسم ماژول رفتاری باشد که داریم اضافه می‌کنیم.

سپس باید همه‌ی توابعی (کالبک‌هایی) را تعریف کنیم که آن ماژول رفتار به آن‌ها نیاز دارد. اگر داریم رفتار شخص دیگری را پیاده‌سازی می‌کنیم، مثل رفتارهای توکار Access یا GenServer در Elixir، فهرست همه‌ی کالبک‌های آن رفتار را در مستندات hexdocs.pm پیدا می‌کنیم.

یک ماژول کالبک محدود به پیاده‌سازی فقط توابعی که بخشی از رفتارش هستند نیست. امکان دارد یک ماژول به‌تنهایی چندین رفتار را پیاده‌سازی کند.

برای مشخص کردن اینکه هر تابع از کدام رفتار می‌آید، باید قبل از هر تابع از ویژگی ماژول @impl استفاده کنیم. مقدار آن باید اسم ماژول رفتاری باشد که این کالبک را تعریف می‌کند.

defmodule BookCollection do
  @behaviour Countable

  defstruct [:list, :owner]

  @impl Countable
  def count(collection) do
    Enum.count(collection.list)
  end

  def mark_as_read(collection, book) do
    # other function unrelated to the Countable behaviour
  end
end

پیاده‌سازی‌های پیش‌فرض کالبک

هنگام تعریف یک رفتار، می‌توان پیاده‌سازی پیش‌فرضی برای یک کالبک فراهم کرد. این پیاده‌سازی باید در عبارت نقل‌قول‌شده‌ی ماکروی __using__/1 تعریف شود. برای اینکه کاربران ماژول رفتار بتوانند پیاده‌سازی پیش‌فرض را بازنویسی کنند، بعد از پیاده‌سازی تابع، ماکروی defoverridable/1 را فراخوانی کنید. این ماکرو یک لیست کلیدواژه می‌پذیرد که کلیدهایش اسم توابع و مقادیرش تعداد آرگومان‌های آن‌ها هستند.

defmodule Countable do
  @callback count(collection :: any) :: pos_integer

  defmacro __using__(_) do
    quote do
      @behaviour Countable
      def count(collection), do: Enum.count(collection)
      defoverridable count: 1
    end
  end
end

توجه کنید که تعریف توابع درون __using__/1 برای هر هدفی جز تعریف پیاده‌سازی‌های پیش‌فرض کالبک توصیه نمی‌شود، اما همیشه می‌توانید توابع را در ماژول دیگری تعریف کنید و آن‌ها را در ماکروی __using__/1 ایمپورت کنید.

ویرایش از طریق GitHub این پیوند در پنجره یا زبانه‌ی جدیدی باز می‌شود

رفتار را یاد بگیرید