Скрыть различные реализации за общим интерфейсом в erlang


У меня есть фрагмент кода erlang, который должен считывать некоторые значения из БД и должен поддерживать пару БД. Я хотел, чтобы мой код каким-то образом не зависел от БД, поэтому я реализовал два разных gen_server, которые регистрируют оба с одним и тем же атомом (db_handler). Я решаю, какую версию следует начать читать .файл приложения.

Два gen_server предоставляют общий handle_call, поэтому я могу использовать в других частях моего приложения что-то вроде:

gen_server:call(db_handler, {do_something, "value1", "value2"})

Это работает, но все же это это сильно связано с тем, что каждая и любая будущая реализация для новой БД должна быть gen_server.

Я думал использовать ! оператор и обработчик команды в handle_info, но все же я думаю, что лучшее решение возможно (может быть, проходя через другой модуль?).

Может ли кто-нибудь дать мне некоторое представление о том, как лучше справиться с чем-то подобным в Эрланге?
2 4

2 ответа:

Для каждого сервера БД добавьте общий интерфейс, чтобы абстрагировать вызов:

-module(db_server1).

...

do_something([Value1,Value2]) -> gen_server:call(db_handler, {do_something, "value1", "value2"}).

...

Еще один, не использующий сервер gen

-module(db_server2).

...

do_something([Value1,Value2]) -> something_else({do_something, "value1", "value2"}).

...

Создайте новый процесс (gen_server: o), который получает в качестве параметра init параметр param, используемый для выбора сервера БД и сохранения его в своем состоянии (например db_server2),

Для каждой функции do_something реализуйте функцию типа:

do_something(Value1,Value2) -> gen_server:call(db_handler, {do_something, ["value1", "value2"]}).

...

handle_call({Func, Args}, _From, DB_server) ->
    R = DB_server:F(Args),
    {reply, R, DB_server}.

То же самое для неблокирующих интерфейсов, использующих cast или эквивалентный

Каждый драйвер базы данных может быть библиотечным модулем, предоставляющим функции для вашего gen_server.

handle_call({do_something, Driver, Value1, Value2}, _From, State) ->
  Reply = Driver:do_something(Value1, Value2),
  {reply, Reply, State}.