[Go言語]Adapterパターンを学ぼう!

こんにちは、KOUKIです。

この記事では、デザインパターンの一つであるAdapterパターンについて、紹介しています。

シチュエーション

Adapterパターンのイメージは、変換機ですね。

例えば、PCにスマートフォンを繋ぎたい場合、私たちはUSB Adapterを使うと思います。Adapterのおかげで、PC(インターフェース)の変更なしで、機能を利用することができるようになるわけですね。

この考え方は、プログラムの世界でも活躍します。どこかの誰かが大昔に作ったプログラムを「変更なし」で利用したい場合、Adapterを作って対処します。

つまり、「元々の構造体の振る舞いを変えたくないけど、それを使った新しい機能を実装したいなぁ」となったときに、威力を発揮します。

Adapterの実装

Adapterパターンを実装していきましょう。

リソースを読み込むための構造体を定義

とあるリソース(情報源)からユーザー情報を読み込むための構造体を定義しましょう。

このReader構造体に、ユーザー情報を表示するメソッド実装したいと思います。提供されるリソースの形式は不明なので、interfaceをパラメータとして渡します。

リソース構造体 ~ その一 ~

さて、先ほど作成したReadResourceに渡せる構造体を作成しましょう。

これは、GitHub REST APIに対して、リクエスト送信する構造体です。

リクエストに成功したらGitHabリポジトリ名とURLがUserInfo構造体にバインドされます。

確認作業1 ~Adapterパターン実装前~

まだ、AdapterのAの字も出てきてませんが、ここまでで実装したコードが動くか確認してみましょう。

OKですね。何度も言うようですが、ReadResourceメソッドの引数はインターフェースなので、GetUserメソッドを実装したインスタンスしか渡すことができません。

リソース構造体 ~ その二 ~

次に、以下の構造体を作成しましょう。この構造体は、元々別のどこかで実装してあったものと仮定してください。

Adapterパターンが必要とされるわけ

JSONRequetsは、GetUserメソッドを実装していないので、ReadResourceメソッドの引数として渡すことができません。

ReadResourceメソッドにJSONRequetsを渡すにはどうしたらいいでしょうか。

普通は、JSONRequets構造体にGetUserメソッドを実装すれば?と思うかもしれません。

しかし、仮に、そう仮にです。JSONRequetsが「他部署のエンジニア(チーム外)や別の業者」により実装され、安易に機能変更ができない場合は、どうすれば良いでしょうか?あるいは、他のプログラムでメチャクチャ使われている重要な構造体で、機能変更するためには、様々な申請手続きを行わなくてはならなかったとしたら?

めんどくせぇぇええええ!!!ですよね(笑)。そんな感じでイメージしてもらえれば幸いです^^

このような時に、Adapterパターンが活躍します。

Adapterを実装

Adapterパターンは、既存の処理(インターフェース)に変更を加えず、よろしくやってくれる実装パターンです。

イメージは「変換機」なので、以下のように実装しましょう。

これで、「JSONRequets -> JsonAdapter -> GetUserメソッドを実装した構造体」の構図になりました。

ここで実装したGetUserメソッドからReadLocalJSONメソッドを呼び出しているところがミソです。

確認作業2 ~Adapterパターン実装後~

先ほど実装したJsonAdapter構造体を使ってみましょう。

ReadResourceメソッドには、GetUserメソッドを実装したインスタンスを渡せます。そのため、JSONAdapterインスタンスのパラメータにJSONRequetsインスタンスを含めて渡すことで、既存の処理を一切修正する事なく、ReadResourceメソッドを利用できるというわけです。

ローカルに、「resource.json」ファイルを用意してください。

プログラムを実行します。

OKですね。

まとめ

Adapterパターンは便利ですが、それ以上に「疎結合を意識したプログラミングを行う」ことが重要だと学べた気がします。

例えば、「func (r *Reader) ReadResource(re Resource) {}」メソッドですが、これのパラメータはインターフェースです。

構造体や特定の値ではなく、インターフェースを渡す事で、プログラミングを蘇結合にできています(と思います)。呼び出し側はこの関数を利用する時、GetUserメソッドを実装した構造体を渡すだけでよく、また、GetUserメソッドの実装内容を呼び出し側で自由に決められます^^

実際の現場では、実装後に機能のアップデートが頻繁にあります。そのため、柔軟に利用できるインターフェースの実装は必須ですね。

それでは、また!

Go言語まとめ

ソースコード

コメントを残す