Goでデザインパターン (Facadeパターン)

Goデザインパターン

Facadeパターンとは

構造に関するデザインパターンの一つ。ライブラリーやフレームワーク等の複雑なシステムに対して、その実装を利用する側から隠蔽し、シンプルなインターフェースを提供することができる。

長所

  • サブシステムの複雑な実装から利用する側を分離することができる。
    (サブシステムのバージョンアップ等があってもFacadeのみの修正で対応が可能になる。)
  • 再帰的にFacadeパターンを適用することで、複雑なシステムを再利用しやすくなる。

短所

  • Facadeを適切に分割する必要がある。分割しない場合、サブシステムの多数のオブジェクトに依存した神オブジェクトになる可能性がある。

利用場面

  • 複雑なサブシステムの一部機能を利用した処理を、簡潔なインターフェースをで用意したい場合。
  • サブシステムを多層構造にしたい場合。(サブシステムの各レベルでのインターフェースを用意する)

クラス図

Facadeパターン
  • Facade
    複雑なサブシステムの高レベルでシンプルなインターフェースをシステム外部に提供する。
    クライアントからのリクエストをサブシステムを利用して処理を行う。サブシステムの実装の詳細について知っている必要あり。
  • Additional Facade
    Facadeを再帰的に作成したり、小さな粒度で構成することによって複雑なFacadeになることを防ぐことができる。
    クライアントからでもほかのFacadeからでも利用可能。
  • Sub System
    多数のオブジェクトからなる複雑なシステム。サブシステム内のオブジェクトはFacadeについては全く認識しない。
  • サブシステムのオブジェクトを直接利用する代わりに、Facadeを利用する。

実装例

Facade

package counter

type WordCounter struct {
	counter
	spliter
	lower
}

func NewWordCounter(sep string) *WordCounter {
	return &WordCounter{
		counter: counter{},
		spliter: spliter{sep: sep},
		lower: lower{},
	}
}

// 複雑な処理を行うAPIを提供する。
// このクラスを利用することで、単語のカウントが容易に行える。
// その代わりに小文字化や文字列分割の機能は利用できない。
// →機能性とシンプルさのトレードオフ
func (c *WordCounter) Count(sentence string) map[string]int {
	lower_sentence := c.lower.lower(sentence)
	word_list := c.spliter.split(lower_sentence)
	counts := c.counter.count(word_list)

	return counts
}

Sub System

ここに記載の実装はFacadeパターンには直接関係はない。

package counter

import (
	"strings"
)

type spliter struct {
	sep string
}

func (s *spliter) split(sentence string) []string {
	return strings.Split(sentence, s.sep)
}
package counter

import (
	"strings"
)

type lower struct {}

func (l *lower) lower(sentence string) string {
	return strings.ToLower(sentence)
}
package counter

type counter struct {}

func (c *counter) count(list []string) map[string]int {
	m := map[string]int{}
	for _, word := range list {
		m[word]++
	}
	return m
}

動作確認

package main

import (
	"fmt"
	"facade/counter"
)

func main() {
	// 利用する側はFacadeの背後にある複雑なサブシステムに依存しない。
	// サブシステムの修正や別サブシステムへの切替の場合は、Facadeクラスの変更のみが必要になる。
	wc := counter.NewWordCounter(" ")
	count := wc.Count("This is a pen. This pen is so good. I like this pen.")
	fmt.Println(count)
}
>> go run .
map[a:1 good.:1 i:1 is:2 like:1 pen:1 pen.:2 so:1 this:3]

コメント

タイトルとURLをコピーしました