Elixir Processes and GenServers - Part 4
7. A Refactored GenServer
First, the business logic.
defmodule Counter.Impl do
@doc "Pure function: Increment counter"
def increment(state), do: state + 1
@doc "Pure function: Decrement counter"
def decrement(state), do: state - 1
@doc "Pure function: Get current value"
def value(state), do: state
end
Next, the GenServer code.
defmodule Counter.Server do
use GenServer
alias Counter.Impl
# Required for GenServer.start_link
def init(initial_value), do: {:ok, initial_value}
def handle_cast(:increment, state), do: {:noreply, Impl.increment(state)}
def handle_cast(:decrement, state), do: {:noreply, Impl.decrement(state)}
def handle_call(:get, _from, state) do
{:reply, Impl.value(state), state}
end
end
Finally, the client API.
defmodule Counter do
@moduledoc "Public API for counter service"
def start_link(initial_value \\ 0) do
GenServer.start_link(Counter.Server, initial_value, name: __MODULE__)
end
def increment, do: GenServer.cast(__MODULE__, :increment)
def decrement, do: GenServer.cast(__MODULE__, :decrement)
def value, do: GenServer.call(__MODULE__, :get)
end
Let’s try it!
{:ok, _pid} = Counter.start_link(10)
Counter.increment()
Counter.decrement()
IO.puts("Counter value: #{Counter.value()}")