最終更新:2020/05/11
この記事の内容は
を参考にGo言語で置き換えた内容になっております。
わかりにくい箇所は私の理解の浅さと説明の下手さが原因であり、本書のせいではありません。
目次
- Adapterパターンとは
- 実装方法
- Adapterパターンの構成
- サンプルコード
- サンプルコードの説明
- サンプルコードの実行
- 設計のヒント
- 関連しているパターン
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パターンの記事を読む