Τα behaviours μάς επιτρέπουν να ορίζουμε διεπαφές (σύνολα συναρτήσεων και μάκρο) σε ένα άρθρωμα behaviour που μπορούν αργότερα να υλοποιηθούν από διαφορετικά αρθρώματα callback. Χάρη στην κοινή διεπαφή, αυτά τα αρθρώματα callback μπορούν να χρησιμοποιηθούν εναλλάξιμα.
Πρόσεξε τη βρετανική ορθογραφία της λέξης "behaviours".
Για να ορίσουμε ένα behaviour, πρέπει να δημιουργήσουμε ένα νέο άρθρωμα και να καθορίσουμε μια λίστα συναρτήσεων που αποτελούν μέρος της επιθυμητής διεπαφής. Κάθε συνάρτηση πρέπει να οριστεί χρησιμοποιώντας το χαρακτηριστικό αρθρώματος @callback. Η σύνταξη είναι ίδια με ένα typespec συνάρτησης (@spec). Πρέπει να καθορίσουμε ένα όνομα συνάρτησης, μια λίστα τύπων ορισμάτων και όλους τους πιθανούς τύπους επιστροφής.
defmodule Countable do
@callback count(collection :: any) :: pos_integer
end
Για να προσθέσουμε ένα υπάρχον behaviour στο άρθρωμά μας (να δημιουργήσουμε ένα άρθρωμα callback), χρησιμοποιούμε το χαρακτηριστικό αρθρώματος @behaviour. Η τιμή του πρέπει να είναι το όνομα του αρθρώματος behaviour που προσθέτουμε.
Στη συνέχεια, πρέπει να ορίσουμε όλες τις συναρτήσεις (callbacks) που απαιτούνται από αυτό το άρθρωμα behaviour. Αν υλοποιούμε το behaviour κάποιου άλλου, όπως τα ενσωματωμένα behaviours Access ή GenServer της Elixir, θα βρούμε τη λίστα όλων των callbacks του behaviour στην τεκμηρίωση στο hexdocs.pm.
Ένα άρθρωμα callback δεν περιορίζεται στην υλοποίηση μόνο των συναρτήσεων που αποτελούν μέρος του behaviour του. Είναι επίσης δυνατό για ένα μεμονωμένο άρθρωμα να υλοποιεί πολλαπλά behaviours.
Για να σημειώσουμε ποια συνάρτηση προέρχεται από ποιο behaviour, πρέπει να χρησιμοποιήσουμε το χαρακτηριστικό αρθρώματος @impl πριν από κάθε συνάρτηση. Η τιμή του πρέπει να είναι το όνομα του αρθρώματος behaviour που ορίζει αυτό το callback.
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
Όταν ορίζουμε ένα behaviour, είναι δυνατό να παρέχουμε μια προεπιλεγμένη υλοποίηση ενός callback. Αυτή η υλοποίηση πρέπει να ορίζεται στην έκφραση quote του μάκρο __using__/1. Για να καταστεί δυνατό στους χρήστες του αρθρώματος behaviour να παρακάμψουν την προεπιλεγμένη υλοποίηση, καλέστε το μάκρο 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 αποθαρρύνεται για οποιονδήποτε άλλο σκοπό εκτός από τον ορισμό προεπιλεγμένων υλοποιήσεων callback, αλλά μπορείς πάντα να ορίσεις συναρτήσεις σε άλλο άρθρωμα και να τις εισάγεις στο μάκρο __using__/1.