0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

お題は不問!Qiita Engineer Festa 2024で記事投稿!
Qiita Engineer Festa20242024年7月17日まで開催中!

【Go】既存のメソッドを追加、変更する方法(Decoratorパターン)

Last updated at Posted at 2024-07-07

はじめに

  • Decoraterパターンは、オブジェクトの振る舞いを追加 / 変更するための非常に強力なデザインパターンです
  • Goには直接的なサポートはありませんが、インタフェースと関数を使うことで、このパターンを実装することができます
  • 本記事では、GoでDecoratorパターンを実装する手法の非常にシンプルな例として、メソッドの出力前後に固定のメッセージを追加するデコレータを紹介します

対象読者

  • Goの関数、メソッド、インタフェースの基礎を理解されている方

Decoratorパターンとは

  • GoFによって定義されたデザインパターンの一つです
  • 既存のメソッドを変更せずに、オブジェクトの振る舞いを追加 / 変更することが可能です

ステップ1:インタフェース定義

以下のようなPrinterインタフェースと、それを実装するMyPrinter型を定義します。

main.go
package main

import "fmt"

// Printerインタフェースの定義
type Printer interface {
    Print()
}

// プリンターの実装
type MyPrinter struct{}
func (mp MyPrinter) Print() {
	fmt.Println("hogehoge")
}

func main() {
	myPrinter := MyPrinter{}
    myPrinter.Print()
}

実行結果

hogehoge

ステップ2:Decorator用の構造体を定義する

Printerを属性として持つ構造体「DecoratedPrinter」を定義します。DecoratedPrinterのPrintメソッドは、引数で受け取ったPrinter.Printメソッド出力前後に固定文字「start」と「end」を出力します。

// Printerを属性として持つ構造体
type DecoratedPrinter struct {
    wrapped Printer
}
func (dp DecoratedPrinter) Print() {
    fmt.Println("start")
    dp.wrapped.Print()
    fmt.Println("end")
}

ステップ3:Decoratorの定義

今回の目玉であるインタフェースをラップする関数「Decorate」の定義です。シグネチャはPrinterを受け取り、Printerを返すというシンプルなものですが、実際にreturnしているのはPrinterではなく、DecoratedPrinterです。

Printerはインタフェース、そして、DecoratedPrinterはPrintメソッドを持っている為、Printerインタフェースを実装しています。Goではこの場合、DecoratedPrinterをPrinterに代入可能です。

// Printerインタフェースをラップする
func Decorate(p Printer) Printer {
    return DecoratedPrinter{wrapped: p}
}

ステップ4:Decoratorを適用する

元のMyPrinterをデコレートします。

func main() {
	printer := Decorate(MyPrinter{})
	printer.Print()
}

完成したソースコード

MyPrinterがデコレートされていることが確認できました。めでたしめでたし。

main.go
package main

import "fmt"

// Printerインタフェースの定義
type Printer interface {
	Print()
}

// プリンターの実装
type MyPrinter struct{}

func (mp MyPrinter) Print() {
	fmt.Println("hogehoge")
}

// Printerを属性として持つ構造体
type DecoratedPrinter struct {
	wrapped Printer
}

func (dp DecoratedPrinter) Print() {
	fmt.Println("start")
	dp.wrapped.Print()
	fmt.Println("end")
}

// Printerインタフェースをラップする
func Decorate(p Printer) Printer {
	return DecoratedPrinter{wrapped: p}
}

func main() {
	printer := Decorate(MyPrinter{})
	printer.Print()
}

実行結果

start
hogehoge
end
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?