Adapterパターン

最終更新:2020/05/11


この記事の内容は

java言語で学ぶデザインパターン

を参考にGo言語で置き換えた内容になっております。

わかりにくい箇所は私の理解の浅さと説明の下手さが原因であり、本書のせいではありません。

目次

  1. Adapterパターンとは
  2. 実装方法
  3. Adapterパターンの構成
  4. サンプルコード
  5. サンプルコードの説明
  6. サンプルコードの実行
  7. 設計のヒント
  8. 関連しているパターン

1. Adapterパターンとは

Adapterパターンは、既存のクラスに対して修正を加えることなく、インタフェースを変更することができます。

もう少し具体的に説明すると、

既にあるコードを使いたいけど、コードを変更すると壊れる可能性があるので、新しいコードを作って既存の関数を呼び出して使う

という手法です。

2. 実装方法

Adapterパターンの実装方法は2種類あります。

  • 継承を使う
  • 移譲を使う

Javaだと継承を使うのが一般的ですが、Goは継承がないので、委譲を利用した手法を使うことになります。

3. Adapterパターンの構成

Target

必要なメソッドを定める役割をもちます。

Adaptee

すでに用意されているメソッドを持っています。 Targetで本来欲しかったメソッドとは、一致しない機能を持ちます。 AdapteeとTargetと一致していないので、Adapterが必要になります。

Adapter

Targetを満たす役割を担います。 Adapteeを使ってTargetを満たす役割を担います。

4. サンプルコード

package adapter import "fmt" // Target type Print interface { PrintWeek() PrintStrong() } // Adapter type PrintBanner struct { B Banner } func (pb *PrintBanner) PrintWeek() { pb.B.ShowWithParen() } func (pb *PrintBanner) PrintStrong() { pb.B.ShowWithAster() } // Adaptee type Banner struct { Msg string } func (b *Banner) ShowWithParen() { fmt.Println("(" + b.Msg + ")") } func (b *Banner) ShowWithAster() { fmt.Println("*" + b.Msg + "*") }

5. サンプルコードの説明

上記のサンプルコードの構成は以下の通りです。

Target

Targetは役割は、必要なメソッドを定めることです。

サンプルコードだとPrintインターフェースが担います。

type Print interface { PrintWeek() PrintStrong() }

必要なメソッドを定義します。

Adaptee

Adapteeの役割、すでに用意されているメソッドを持ってることです。 Targetで本来欲しかったメソッドとは、一致しない機能を持ちます。

サンプルコードでは、Banner構造体が当てはまります。

type Banner struct { Msg string } func (b *Banner) ShowWithParen() { fmt.Println("(" + b.Msg + ")") } func (b *Banner) ShowWithAster() { fmt.Println("*" + b.Msg + "*") }

Adapter

AdapterはTargetを満たす役割を担います。 Adapteeを使ってTargetを満たす役割を担います。

サンプルコードでは、PrintBanner構造体がAdapterです。

type PrintBanner struct { B Banner } func (pb *PrintBanner) PrintWeek() { pb.B.ShowWithParen() } func (pb *PrintBanner) PrintStrong() { pb.B.ShowWithAster() }

移譲を使ってPrintBanner(Adaptee()を利用します。

6. サンプルコードの実行

サンプルコードをmain関数で呼び出します。

package main import "github.com/java-lang-programming/marsa/adapter" func main() { print := &adapter.PrintBanner{ B: adapter.Banner{ Msg: "Hello", }, } print.PrintStrong() print.PrintWeek() }

実行すると以下が出力されます。

# go run main.go *Hello* (Hello)

7. 設計のヒント

どんな時に使うのか

Adapterパターンは、テスト済みでバグの少ない実績のあるコードを再利用したい場合に利用します。

つまり。既存のクラスに一皮被せて必要とするクラスを作ります。

なので、TargetとAdapteeの機能があまりにかけ離れている場合、Adapterパターンを使うべきではありません。

8. 関連しているパターン

Decoratorパターン

Decoratorパターンは、透過的なインターフェースを保ったまま、オブジェクトを次々にかぶせて機能を追加します。

DecoratorパターンもAdapterパターンと機能追加という点は同じですが、インターフェースを変更しないで機能を追加するパターンになります。

Decoratorパターンの記事を読む