У меня нет точного рисунка, чтобы объяснить это, но у меня есть эта глава и одна после того, как показано, как построить gen_server, начиная с принципов абстракции, стоящих за ним.
Чтобы помочь с отдельными компонентами:
реализация поведения
Само поведение немного похоже на то, что показано в главе, которую я связал ранее. Это модуль с кучей функций, выполняющих все за вас: получение сообщений, определение функций и скрытых протоколов для обмена данными и т. Д. Усовершенствованный OTP-контент содержит специальные виды сообщений, используемых для обновления программного обеспечения, а также специальный код для параметров трассировки.
контейнер поведения
Я не уверен, что это должно быть. Может просто модуль с названием поведения?
интерфейс поведения
В том же модуле, в котором реализована ваша реализация поведения, вы должны определить функцию behaviour_info/1
. Эта функция сообщит компилятору Erlang, что от любого модуля, который имеет -behaviour(SomeModuleName)
, ожидаются некоторые обратные вызовы. SomeModuleName
эквивалентен файлу SomeModuleName.erl
(и .beam
), который содержит реализацию и функцию поведением_info.
модуль обратного вызова
Модуль, который будет содержать весь определенный код, обрабатывая все пользовательские вещи.
функции обратного вызова
Все, что не является общим, передается модулю обратного вызова в виде YourModule:SomeCall(Args)
. Они предоставляются вашим модулем, в котором есть строка -behaviour(gen_server).
.
API функции
Модуль обратного вызова имеет два интерфейса, если хотите: один для поведения gen_server
(init / 0, handle_call / 3, handle_info / 2, handle_cast / 2, terminate / 2, code_change / 3) и один для пользователя (запустить сервер, отправить некоторую информацию, запросить некоторую информацию обратно).
Я мог бы попытаться описать это так
---------------------------------------------------------------------
| some process | server process |
------------------------+--------------------------------------------
[client] | [callback] : [behaviour]
| :
callback:start >-------|---------------------:--> starting the process
| : V
| : |
| init() <-----:-----------`
| | :
| `-----------:------> initial state
{ok, Pid} <----------|---------------------:----------,/
| :
callback:store >------|---------------------:--> handles message
(calls the process) | (formats msg) : V
| : |
| handle_call() <--:-----------`
| | :
| `----------:--> updates state, sends reply
| : V
| : |
gets result <--------|---------------------:--------`
| :
Все общие части находятся справа от серверного процесса, в пределах поведения, а все конкретные части находятся слева (обратный вызов). Клиент использует API / интерфейс модуля обратного вызова для связи с процессом сервера и воздействия на него.
Вы должны рассматривать поведение как своего рода очень общий сегмент кода, который иногда отдает свой поток выполнения (для более точных частей, таких как получение и отправка сообщений) конкретному коду (как реагировать на эти сообщения).
Надеюсь, это поможет.