Golangで、デザインパターン「Template Method」を学ぶ

GoFのデザインパターンを学習する素材として、書籍「[増補改訂版Java言語で学ぶデザインパターン入門](https://www.hyuki.com/dp/)」が参考になるみたいですね。
取り上げられている実例は、JAVAベースのため、Pythonで同等のプラクティスに挑んだことがありました。
[Qiita記事: "Pythonで、デザインパターン「Template Method」を学ぶ"](https://qiita.com/ttsubo/items/475ac4810ae44c0ea1bd)

今回は、Pythonで実装した”Template Method”のサンプルアプリをGolangで実装し直してみました。

# ■ Template Method（テンプレート・メソッド・パターン）
Template Methodパターン（テンプレート・メソッド・パターン）とは、GoF(Gang of Four; 4人のギャングたち)によって定義されたデザインパターンの1つである。「振る舞いに関するパターン」に属する。Template Methodパターンの目的は、ある処理のおおまかなアルゴリズムをあらかじめ決めておいて、そのアルゴリズムの具体的な設計をサブクラスに任せることである。そのため、システムのフレームワークを構築するための手段としてよく活用される。

## UML class diagram
![templatemethod.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103595/1d868272-89e4-9c9b-6040-ca213d1875b9.png)
[(以上、ウィキペディア（Wikipedia）より引用)](https://ja.wikipedia.org/wiki/Template_Method_パターン)

# ■ "Template Method"のサンプルプログラム
実際に、Template Methodパターンを活用したサンプルプログラムを動かしてみて、次のような動作の様子を確認したいと思います。

- 文字"H"を、５回連続で表示する。さらに前後では、"**<<**", "**>>**"で囲って表示する
- 文字列"Hello, World!"を５回連続で表示する。さらに、枠線で囲って表示する

```console
$ go run Main.go 
<<HHHHH>>

+-------------+
|Hello, World!|
|Hello, World!|
|Hello, World!|
|Hello, World!|
|Hello, World!|
+-------------+
```

# ■ サンプルプログラムの詳細
Gitリポジトリにも、同様のコードをアップしています。
https://github.com/ttsubo/study_of_design_pattern_with_golang/tree/master/TemplateMethod

- ディレクトリ構成

```console
.
├── Main.go
└── templatemethod
    └── display.go
```

## (1) AbstractClass（抽象クラス）の役
`AbstractClass`役は、テンプレートメソッドを実装します。また、テンプレートメソッドで使っている抽象メソッドを宣言します。この抽象メソッドは、サブクラスである`ConcreteClass`役によって実装されます。
サンプルプログラムでは、`Printer`インタフェースと`AbstractDisplay`構造体が、この役を努めます。

```go:templatemethod/display.go
package templateMethod

import "fmt"

// Printer is interface
type Printer interface {
	open()
	print()
	close()
}

// AbstractDisplay is struct
type AbstractDisplay struct {
	printer Printer
}

// Display for printout result
func (a *AbstractDisplay) Display() {
	a.printer.open()
	for i := 0; i < 5; i++ {
		a.printer.print()
	}
	a.printer.close()
}
```

## (2) ConcreteClass（具象クラス）の役
`AbstractClass`役で定義された抽象クラスを具体的に実装します。ここで実装したメソッドは、`AbstractClass`役のテンプレートメソッドから呼び出されます。
サンプルプログラムでは、`CharDisplay`構造体と、`StringDisplay`構造体が、この役を努めます。

```go:templatemethod/display.go
// CharDisplay is struct
type CharDisplay struct {
	*AbstractDisplay
	ch byte
}

// NewCharDisplay func for initializing CharDisplay
func NewCharDisplay(ch byte) *CharDisplay {
	charDisplay := &CharDisplay{
		AbstractDisplay: &AbstractDisplay{},
		ch:              ch,
	}
	charDisplay.printer = charDisplay
	return charDisplay
}

func (c *CharDisplay) open() {
	fmt.Print("<<")
}
func (c *CharDisplay) print() {
	fmt.Print(string(c.ch))
}
func (c *CharDisplay) close() {
	fmt.Println(">>")
}
```
```go:templatemethod/display.go
// StringDisplay is struct
type StringDisplay struct {
	*AbstractDisplay
	str   string
	width int
}

// NewStringDisplay func for initalizing StringDisplay
func NewStringDisplay(str string) *StringDisplay {
	stringDisplay := &StringDisplay{
		AbstractDisplay: &AbstractDisplay{},
		str:             str,
		width:           len(str),
	}
	stringDisplay.printer = stringDisplay
	return stringDisplay
}

func (s *StringDisplay) open() {
	s.printLine()
}
func (s *StringDisplay) print() {
	fmt.Printf("%s%s%s\n", "|", s.str, "|")
}
func (s *StringDisplay) close() {
	s.printLine()
}

func (s *StringDisplay) printLine() {
	fmt.Print("+")
	for i := 0; i < s.width; i++ {
		fmt.Print("-")
	}
	fmt.Println("+")
}
```

## (3) Client（利用者）の役
サンプルプログラムでは、`startMain`関数が、この役を努めます。

```go:Main.go
package main

import (
	"fmt"

	templateMethod "./templatemethod"
)

func startMain() {
	d1 := templateMethod.NewCharDisplay('H')
	d2 := templateMethod.NewStringDisplay("Hello, World!")
	d1.Display()
	fmt.Println("")
	d2.Display()
}

func main() {
	startMain()
}
```

# ■ 参考URL
- [Pythonで、デザインパターン「Template Method」を学ぶ](https://qiita.com/ttsubo/items/475ac4810ae44c0ea1bd)