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

こんにちは、KOUKIです。

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

ソースコードは、以下のYouTube動画を参考にしています。

デザインパターンまとめ

シチュエーション

スポンジケーキの上に、生クリームが乗っていて、さらにその上に美味しそうなイチゴがデコレーションされているショートケーキをイメージしてください。

これをプログラムの観点から観察すると、元々の機能(スポンジケーキ)に新しい機能(生クリームやいちご)が実装されている、と解釈することができると思います。

この様に、既存の機能に何か新しい機能を実装したい場合、Decoratorパターンを検討しましょう。

Decoratorパターン

装飾元となるプログラムを実装してからDecoratorパターンを適用します。

円周率計算プログラム

円周率を計算するプログラムを実装します。

このPi関数は、ショートケーキの例で言うところのスポンジです。

プログラムを実行してみましょう。

Decorator ~ ロガー関数 ~

このプログラムが完了するまでに、どの程度の時間かかったかロガー(Decorator)を実装して算出してみましょう。

typeの定義

まず、typeを定義してください。

これは、Pi関数のパラメータ/戻り値と同じ型です。

Decoratorパターンを実装する上で必須ではありませんが、typeを定義するとわかりやすいプログラムを実装できます。

デザインパターンの適用

以下に実装する関数がDecoratorです。

引数にはデコレーション元(Pi関数)とロガーを渡し、以下の様に呼び出します。

変数fには、piFunc typeのfn := func(n int) (result float64)が格納されています。

そして、この無名関数内で「タイムスタンプ + do(Pi関数)」を定義することで、元々の機能(Pi関数)とロガー機能(wrapLogger)をデコレーションすることができます。

補足ですが、timeスタンプを取るとき、deferキーワードを使っています。こうすれば、do(Pi関数)の実行後にtimestampを取得することができます。

Decoratorは、ミドルウェアを実装するとき重宝しそうですね。

Decorator ~ キャッシュ ~

更に理解を深めるために、別のDecoratorを実装しましょう。

wrapCache関数は、sync.Mapを使ってキャッシュの仕組みを提供しています。

do関数の実行前に、sync.Mapからキャッシュの存在を確認し、存在していない場合は保存 + do関数実行、存在する場合はキャッシュからデータを返します。

do関数の実行 + キャッシュの保存がなくなる分、2回目以降の実行が早くなるはずです。

だいぶ早くなりましたね。

現場でもプログラムの速度を上げるためにキャッシュを実装するので、テクニックとして覚えておいて損はないと思います。

Decoratorのメリット

Decoratorは、再利用がしやすいです

例えば、Pi関数と同じパラメータ/戻り値の関数を定義したとします。

この関数に、これまで実装したデコレーターを適用することが可能です。

OKですね。覚えるとめちゃくちゃ便利なパターンです。

まとめ

恐らく、Decoratorパターンを実装する上で大切なのは、だと思います。

再利用性を考えると、ここに定義する型はなるべく単純なものにしておくべきです。パラメータが簡単だとテストもしやすいですしね^^

Decoratorパターンは、使いこなすと強力なツールになりそうなので、ガンガン実装していきたいと思います!

それでは、また!

Go言語まとめ

ソースコード

コメントを残す