2020-05-07 00:10:23
オープン・クローズドの原則をElixirで試す_No1
「多分こういうことだろう」という気持ちで試します。
目次
- はじめに
- サンプルお題
- バージョン情報
- ディレクトリ構成
- 流れと各ファイルの説明
- ソース
- 実行の様子
- 参考資料
- 余談
はじめに
「オープン・クローズドの原則」自体への理解度は「これって要するにストラテジーパターンなのでは?」という程度です。意識して最初から実装したことはありません。
サンプルお題
ファイルに書き込む処理を考えます。textファイル, csvファイル, imageファイルの3種類に書き込む write() を呼び出します
バージョン情報
/home/trial/ocp_file # elixir -v
Erlang/OTP 22 [erts-10.7.1] [source] [64-bit] [smp:2:2] [ds:2:2:10] [async-threads:1]
Elixir 1.9.4 (compiled with Erlang/OTP 22)
ディレクトリ構成
ocp_file
├── lib
│ ├── controller
│ │ └── file_service.ex
│ ├── files
│ │ ├── csv.ex
│ │ ├── image.ex
│ │ ├── myfile.ex
│ │ └── text.ex
│ └── ocp_file.ex
流れと各ファイルの説明
クラス図っぽいものを以下に記載します。
ocp_file.ex ─> file_service.ex ─> myfile.ex <--- text.ex, csv.ex, pdf,ex, image.ex
- ocp_file.ex
- 実際にコマンドから実行するモジュール
- file_service.ex
- 3種類のモジュールから1つのモジュールを返すモジュール
- myfile.ex
- behaviour で振る舞いを定義するモジュール
- behaviour とは elixir において仕様をモジュールに要求する仕組みです
- Java, PHP などの interface と似たものです
- elixir の behaviour は実装を強制しません
- text.ex, csv.ex, image.ex
- myfile.ex の振る舞いを実装するモジュールたち
ソース
ocp_file.ex
defmodule OcpFile do
def index(type) do
file = Controller.FileService.newFileModule(type)
file.write()
end
end
file_service.ex
defmodule Controller.FileService do
def newFileModule("csv"), do: Files.Csv
def newFileModule("text"), do: Files.Text
def newFileModule("image"), do: Files.Image
end
myfile.ex
defmodule Files.Myfile do
@callback write() :: String.t()
end
text.ex
defmodule Files.Text do
@behaviour Files.Myfile
@impl Files.Myfile
def write() do
"TextFile"
end
end
csv.ex
defmodule Files.Csv do
@behaviour Files.Myfile
@impl Files.Myfile
def write() do
"CsvFile"
end
end
image.ex
defmodule Files.Image do
@behaviour Files.Myfile
@impl Files.Myfile
def write() do
"ImageFile"
end
end
実行の様子
/home/trial/ocp_file # iex -S mix
Erlang/OTP 22 [erts-10.7.1] [source] [64-bit] [smp:2:2] [ds:2:2:10] [async-threads:1]
Interactive Elixir (1.9.4) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> OcpFile.
MixProject index/1
iex(1)> OcpFile.index("text")
"TextFile"
iex(2)> OcpFile.index("csv")
"CsvFile"
iex(3)> OcpFile.index("image")
"ImageFile"
iex(4)>
OcpFile.index の引数に応じて異なるモジュールの振る舞いを実行できていることが確認できました。
参考資料
- 書籍「clean architecture 達人に学ぶソフトウェアの構造と設計」
- https://thinkit.co.jp/article/13274
- https://medium.com/eureka-engineering/go-open-closed-principle-977f1b5d3db0
余談
書籍「clean architecture 達人に学ぶソフトウェアの構造と設計」のオープンクローズド原則の説明に出てくるクラス図が今の自分には良く分からない。実際のソースを見たい。最終的に Interactor コンポーネントを実行するのかな。