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

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

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

# ■ Facade（ファサード・パターン）
Facadeパターンあるいは Façadeパターン（ファサード・パターン）とは、GoF（Gang of Four; 4人のギャングたち）によって定義された、コンピュータソフトウェアのデザインパターンの1つである。Facade（ファサード）とは「建物の正面」を意味する。異なるサブシステムを単純な操作だけを持ったFacadeクラスで結び、サブシステム間の独立性を高める事を目的とする。

## UML class and sequence diagram
![W3sDesign_Facade_Design_Pattern_UML.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103595/ee3e77d2-4cf8-c88f-f2f4-d4d0b1e30cbb.jpeg)
## UML class diagram
![Example_of_Facade_design_pattern_in_UML.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103595/7abb8840-fbd6-dfcc-ff09-a8a3f087599e.png)
[(以上、ウィキペディア（Wikipedia）より引用)](https://ja.wikipedia.org/wiki/Facade_パターン)


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

```console
$ go run Main.go 
welcome1.html is created for hyuki@hyuki.com (Hiroshi Yuki)
welcome2.html is created for mamoru@hyuki.com (Mamoru Takahashi)
```
サンプルプログラムを起動すると、２つのhtmlファイルが生成されます。
おのおのを、Webブラウザを確認してみるとこんな感じになりました。

- welcome1.html

|![welcome1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103595/75125acd-739e-ac00-37fa-ce236b0cadb1.png)|
|:-:|

- welcome2.html

|![welcome2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103595/6ef893f4-ed6e-39f3-70de-f7a16d12835f.png)|
|:-:|

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

- ディレクトリ構成

```console
.
├── Main.go
├── facade
│   ├── database.go
│   ├── html_writer.go
│   └── page_maker.go
├── maildata.json
├── welcome1.html
└── welcome2.html
```
## (1) Facade（正面）の役
`Facade`役は、システムを構成しているその他大勢の役の「シンプルな窓口」となります。`Facade`役は、高レベルでシンプルなインタフェースをシステム外部に提供します。
サンプルプログラムでは、`PageMaker`構造体が、この役を努めます。

```go:facade/page_maker.go
package facade

import (
	"fmt"
	"os"
)

// PageMaker is struct
type PageMaker struct {
}

// Pagemaker is variable
var Pagemaker = &PageMaker{}

// MakeWelcomePage func for making welcome page
func (p *PageMaker) MakeWelcomePage(mailaddr, filename string) {
	username := ""
	database := &Database{}
	prop := database.getProperties("maildata")
	for _, person := range prop {
		if person.Mail == mailaddr {
			username = person.Name
		}
	}
	file, _ := os.Create(filename)
	writer := &HTMLWriter{file}
	writer.title(fmt.Sprintf("Welcom to %s's page!", username))
	writer.paragraph("We'll wait for your sending")
	writer.mailto(mailaddr, username)
	writer.close()
	fmt.Printf("%s is created for %s (%s)\n", filename, mailaddr, username)
}
```
## (2) システムを構成しているその他大勢の役
その他大勢の役は、それぞれの仕事を行いますが、`Facade`役のことは意識しません。`Facade`役から呼び出されて仕事を行いますが、その他大勢の役の方から`Facade`役を呼び出すことはありません。
サンプルプログラムでは、`Database`構造体と、`HTMLWriter`構造体が、この役を努めます。

```go:facade/database.go
package facade

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
)

// Database is struct
type Database struct {
}

// Person is struct
type Person struct {
	Name string `json:"name"`
	Mail string `json:"mail"`
}

var maildata []Person

func (d *Database) getProperties(dbname string) []Person {
	filename := dbname + ".json"
	jsonString, err := ioutil.ReadFile(filename)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	if err = json.Unmarshal(jsonString, &maildata); err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	return maildata
}
```
```go:maildata.json
[
  {
    "mail": "hyuki@hyuki.com", 
    "name": "Hiroshi Yuki"
  }, 
  {
    "mail": "hanako@hyuki.com", 
    "name": "Hananko Sato"
  }, 
  {
    "mail": "tomura@hyuki.com", 
    "name": "Tomura"
  }, 
  {
    "mail": "mamoru@hyuki.com", 
    "name": "Mamoru Takahashi"
  }
]
```
```go:facade/html_writer.go
package facade

import (
	"fmt"
	"os"
)

// HTMLWriter is struct
type HTMLWriter struct {
	writer *os.File
}

func (h *HTMLWriter) title(title string) {
	h.writer.Write([]byte("<html>\n"))
	h.writer.Write([]byte("<head>"))
	h.writer.Write([]byte(fmt.Sprintf("<title>%s</title>", title)))
	h.writer.Write([]byte("</head>\n"))
	h.writer.Write([]byte("<body>\n"))
	h.writer.Write([]byte(fmt.Sprintf("<h1>%s</h1>\n", title)))
}

func (h *HTMLWriter) paragraph(msg string) {
	h.writer.Write([]byte(fmt.Sprintf("<p>%s</p>\n", msg)))
}

func (h *HTMLWriter) link(href, caption string) {
	h.writer.Write([]byte(fmt.Sprintf("<a href=\"%s\">%s</a>", href, caption)))
}

func (h *HTMLWriter) mailto(mailaddr, username string) {
	h.link(fmt.Sprintf("mailto:%s", mailaddr), username)
}

func (h *HTMLWriter) close() {
	h.writer.Write([]byte("</body>\n"))
	h.writer.Write([]byte("</html>\n"))
	h.writer.Close()
}
```
## (3) Client（依頼人）の役
Facadeパターンを利用する役です。
サンプルプログラムでは、`startMain`関数が、この役を努めます。

```go:Main.go
package main

import (
	"./facade"
)

func startMain() {
	facade.Pagemaker.MakeWelcomePage("hyuki@hyuki.com", "welcome1.html")
	facade.Pagemaker.MakeWelcomePage("mamoru@hyuki.com", "welcome2.html")
}

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

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