こんにちは、KOUKIです。
この記事では、デザインパターンの一つであるFacade(ファサード)パターンについて紹介します。
<目次>
デザインパターンまとめ
シチュエーション
Facadeパターンは、複数のクラス(Go言語にはクラスがないので構造体)が絡むような複雑な処理を吸収する窓口を作ります。
身近な例としてログイン処理を考えてみましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
package main import ( "math/rand" "time" ) func init() { rand.Seed(time.Now().UnixNano()) } type Token struct { token int } func NewToken() *Token { return &Token{ token: rand.Intn(100), } } // トークンを取得 func (t *Token) GetToken() int { return t.token } type User struct { name, password string } func NewUser(name, password string) *User { return &User{ name: name, password: password, } } // ログイン処理 func (u *User) Login() bool { return true } |
Tokenを取得する処理とログインする処理を書きました(中身は実装してませんが)。
このソースコードは、ユーザー側で以下の様に利用します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
func main() { // インスタンス化する t := NewToken() u := NewUser("selfnote", "hogehoge") // トークンを取得 validToken := t.GetToken() // Tokenが存在しているか if validToken == 0 { // ログインする u.Login() } } |
ご覧の通り、「ログインをする」という目的のために利用者側で色々な処理の呼び出しが必要です。このような場合は、単一のインターフェースを用意すると処理がシンプルになります。
Facadeパターンを適用する
Facadeパターンで実装してみましょう。
※本記事の目的はFacadeパターンを紹介することなので、サンプルコードは簡略的に書いてます
構造体を包む
Facadeパターンでやりたいことは複数の構造体からなる処理の呼び出しに単一のインターフェースを提供して一元管理することです。
そのため、構造体を包む構造体を定義します。
1 2 3 4 5 |
// 構造体を包む type Login struct { token *Token user *User } |
コンストラクタの定義
次に、コンストラクタを定義します。
1 2 3 4 5 6 7 8 9 |
func NewLogin(name, password string) *Login { // インスタンス化する t := NewToken() u := NewUser("selfnote", "hogehoge") return &Login{ token: t, user: u, } } |
ここでは、TokenとUserをインスタンス化しています。
共通のインターフェースを作る
次に、複数の処理をひとまとめにするメソッドを定義します。
1 2 3 4 5 6 7 8 9 10 11 |
// 共通のインターフェースを作る func (l *Login) Login() { // トークンを取得 validToken := l.token.GetToken() // Tokenが存在しているか if validToken == 0 { // ログインする l.user.Login() } } |
使ってみよう
このコードは、以下の様に呼び出すことができます。
1 2 3 4 |
func main() { l := NewLogin("selfnote", "hogehoge") l.Login() } |
共通のインターフェースが提供されたので、呼び出し処理がスッキリしたと思います。
まとめ
今回は、ログイン処理を例にあげましたが、実際のログインの処理はこんな簡単ではないですねw
強調したかったことは、以下のことです。
機能呼び出し → 複数の処理をAppでゴニョゴニョ → 期待した結果を取得
この「複数の処理をAppでゴニョゴニョ」の考え方は、マイクロサービスなんかで使えるんじゃないかなと思いました。
マイクロサービスは、独立したAppを連携させて管理/運用する手法ですが、細分化するが故に、呼び出しが辛くなっていくと思うんですよね。
それを共通のインターフェースを作って、App側でよろしくやってくれるように実装すれば、利用者側も使いやすいコードになると思います。
ガンガン実装していきたいですね。
それでは、また!
Go言語まとめ
ソースコード
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
package main import ( "math/rand" "time" ) func init() { rand.Seed(time.Now().UnixNano()) } type Token struct { token int } func NewToken() *Token { return &Token{ token: rand.Intn(100), } } // トークンを取得 func (t *Token) GetToken() int { return t.token } type User struct { name, password string } func NewUser(name, password string) *User { return &User{ name: name, password: password, } } // ログイン処理 func (u *User) Login() bool { return true } // 構造体を包む type Login struct { token *Token user *User } func NewLogin(name, password string) *Login { // インスタンス化する t := NewToken() u := NewUser("selfnote", "hogehoge") return &Login{ token: t, user: u, } } // 共通のインターフェースを作る func (l *Login) Login() { // トークンを取得 validToken := l.token.GetToken() // Tokenが存在しているか if validToken == 0 { // ログインする l.user.Login() } } func main() { l := NewLogin("selfnote", "hogehoge") l.Login() } |
コメントを残す
コメントを投稿するにはログインしてください。