Скрыть различные реализации за общим интерфейсом в erlang
У меня есть фрагмент кода erlang, который должен считывать некоторые значения из БД и должен поддерживать пару БД. Я хотел, чтобы мой код каким-то образом не зависел от БД, поэтому я реализовал два разных gen_server, которые регистрируют оба с одним и тем же атомом (db_handler). Я решаю, какую версию следует начать читать .файл приложения.
Два gen_server предоставляют общий handle_call, поэтому я могу использовать в других частях моего приложения что-то вроде:
gen_server:call(db_handler, {do_something, "value1", "value2"})
Это работает, но все же это это сильно связано с тем, что каждая и любая будущая реализация для новой БД должна быть gen_server.
Я думал использовать ! оператор и обработчик команды в handle_info, но все же я думаю, что лучшее решение возможно (может быть, проходя через другой модуль?).
Может ли кто-нибудь дать мне некоторое представление о том, как лучше справиться с чем-то подобным в Эрланге?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 или эквивалентный