LoginSignup
2

More than 3 years have passed since last update.

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

Last updated at Posted at 2020-03-26

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

今回は、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

UML class diagram

Example_of_Facade_design_pattern_in_UML.png
(以上、ウィキペディア(Wikipedia)より引用)

■ "Facade"のサンプルプログラム

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

$ go run Main.go 
welcome1.html is created for hyuki@hyuki.com (Hiroshi Yuki)
welcome2.html is created for mamoru@hyuki.com (Mamoru Takahashi)

サンプルプログラムを起動すると、2つのhtmlファイルが生成されます。
おのおのを、Webブラウザを確認してみるとこんな感じになりました。

  • welcome1.html
welcome1.png
  • welcome2.html
welcome2.png

■ サンプルプログラムの詳細

Gitリポジトリにも、同様のコードをアップしています。
https://github.com/ttsubo/study_of_design_pattern_with_golang/tree/master/Facade

  • ディレクトリ構成
.
├── Main.go
├── facade
│   ├── database.go
│   ├── html_writer.go
│   └── page_maker.go
├── maildata.json
├── welcome1.html
└── welcome2.html

(1) Facade(正面)の役

Facade役は、システムを構成しているその他大勢の役の「シンプルな窓口」となります。Facade役は、高レベルでシンプルなインタフェースをシステム外部に提供します。
サンプルプログラムでは、PageMaker構造体が、この役を努めます。

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構造体が、この役を努めます。

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
}
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"
  }
]
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関数が、この役を努めます。

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

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
2