Parcours
/
Elixir
Elixir
/
Programme
/
Comportements
Co

Comportements en Elixir

1 exercice

À propos de Comportements

Les behaviours permettent de définir des interfaces (des ensembles de fonctions et de macros) dans un module de behaviour, que différents modules de callback pourront ensuite implémenter. Grâce à cette interface commune, ces modules de callback peuvent être utilisés indifféremment.

Note

Remarque l'orthographe britannique de « behaviours ».

Définis des behaviours

Pour définir un behaviour, on crée un nouveau module et on y spécifie une liste de fonctions qui font partie de l'interface voulue. Chaque fonction doit être définie à l'aide de l'attribut de module @callback. La syntaxe est identique à celle d'une spécification de type de fonction (@spec). Il faut préciser un nom de fonction, une liste de types d'arguments et tous les types de retour possibles.

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

Implémente des behaviours

Pour ajouter un behaviour existant à notre module (créer un module de callback), on utilise l'attribut de module @behaviour. Sa valeur doit être le nom du module de behaviour que l'on ajoute.

Ensuite, il faut définir toutes les fonctions (callbacks) requises par ce module de behaviour. Si l'on implémente le behaviour de quelqu'un d'autre, comme les behaviours Access ou GenServer intégrés à Elixir, on trouvera la liste de tous les callbacks de ce behaviour dans la documentation sur hexdocs.pm.

Un module de callback n'est pas limité à l'implémentation des seules fonctions qui font partie de son behaviour. Un même module peut aussi implémenter plusieurs behaviours.

Pour indiquer de quel behaviour vient chaque fonction, on utilise l'attribut de module @impl devant chaque fonction. Sa valeur doit être le nom du module de behaviour qui définit ce 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

Implémentations par défaut des callbacks

Lorsque l'on définit un behaviour, il est possible de fournir une implémentation par défaut d'un callback. Cette implémentation doit être définie dans l'expression quoted de la macro __using__/1. Pour que les utilisateurs du module de behaviour puissent redéfinir l'implémentation par défaut, on appelle la macro defoverridable/1 après l'implémentation de la fonction. Elle accepte une liste de mots-clés dont les clés sont des noms de fonctions et les valeurs des arités de fonctions.

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

Note que définir des fonctions à l'intérieur de __using__/1 est déconseillé pour toute autre raison que définir des implémentations de callback par défaut, mais tu peux toujours définir des fonctions dans un autre module et les importer dans la macro __using__/1.

Modifie via GitHub Le lien s'ouvre dans une nouvelle fenêtre ou un nouvel onglet

Apprends Comportements