如何在一个模块 Elixir 中获取所有重复的 genserver 调用

how get all duplicated genserver calls in one module Elixir

我已经创建了 2 个 genservers。

camera.ex

defmodule Camera do
  use GenServer

  defmodule Attributes do
    defstruct ~w|name url password port username id owner_id status|a
  end

  def start_link(state \ %Attributes{} ) do
    GenServer.start_link(__MODULE__, %Attributes{state | id: make_ref()})
  end

  def init(state) do
    {:ok, state}
  end

  def details(pid) do
    GenServer.call(pid, :get)
  end

  def update(pid, map) do
    GenServer.cast(pid, {:update, map})
  end

  def handle_call(:get, _from, state) do
    {:reply, state, state}
  end

  def handle_cast({:update, map}, state) do
    {:noreply, Map.merge(map, state)}
  end
end

我有与 user.ex 相同的 Genserver,两者之间的唯一区别是属性。

在相机里

  defmodule Attributes do
    defstruct ~w|name url password port username id owner_id status|a
  end

并在用户 its

  defmodule Attributes do
    defstruct ~w|id username|a
  end

所有其他调用都是重复的,我正在保存 user/camera 或更新用户或相机。

我如何制作可以在用户和相机中使用的通用模块,它会采用该模块的行为,这将有助于减少重复。谢谢。

有两种不同的方法:一种是使用defdelegate/2而不是代码重复。


另一种方法是使用元编程。

defmodule Scaffold do
  @moduledoc false

  defmacro __using__(opts) do
    quote generated: true, location: :keep do
      use GenServer

      defmodule Attributes, do: defstruct unquote(opts)

      def start_link(state \ %Attributes{}) do
        GenServer.start_link(__MODULE__,
          %Attributes{state | id: make_ref()})
      end

      def init(state), do: {:ok, state}

      def details(pid),
        do: GenServer.call(pid, :get)

      def update(pid, map),
        do: GenServer.cast(pid, {:update, map})

      def handle_call(:get, _from, state),
        do: {:reply, state, state}

      def handle_cast({:update, map}, state),
        do: {:noreply, Map.merge(map, state)}
    end
  end
end

并将其用作

defmodule Camera do
  use Scaffold, [:name, :url, ...]
end