ال

السلوكيات في 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 يفتح الرابط في نافذة أو علامة تبويب جديدة

تعلّم السلوكيات