Mediatorパターンとは
振る舞いに関するデザインパターンの一つ。オブジェクト間の複雑な依存性をMediatorに分離することで複雑さを軽減する。またオブジェクト間の通信を制限し、Mediatorを通した作業を強制することができる。ユーザー登録フォーム等で各コンポーネント間(テキストフィールドやチェックボックス)の状態管理に利用される。
長所
- Component間の通信に対する責任を分離することができる。(単一責任の原則)
- 新規Mediatorの追加に対してクライアント側処理の変更が必要ない。(開放閉鎖の原則)
- Component間の依存を軽減できる。
- 個々のComponentの再利用が容易になる。
(Mediator未導入の場合はComponent内に他Componentとの通信処理が必要)
短所
- Component間の依存性を一か所で管理する都合上、Mediatorが神オブジェクトになる可能性がある。
利用場面
- 他Componentへの依存度が高く、再利用が難しい場合。
- Component間の違う関係性のためにサブクラスを必要とする場合。
(チェックボックスの選択状態に依存していたのを、テキストボックスの入力状況に依存するようにしたい等)
クラス図

- Mediator
様々なイベントに関して、ComponentからMediatorへ通知を行うために使用する各種メソッドを宣言する。
通常は通知メソッド一つを宣言する。 - Concrete Mediator
各Component間の関係を隠蔽し、調整を行うメソッドを実装する。各種イベントに対するComponentの状態更新等の処理を行う。 - Component
MediatorとMediatorインターフェースを通して通信を行うメソッドを宣言する。
Meditatorインターフェースに対してのみ依存するため、多種のConcrete Mediatorと利用可能。 - Concrete Components
Componentインターフェースで宣言されたインターフェースを実装する。
各Component間は全く通信を行わない。Component間の関係はすべてConcrete Mediator内で実装される。
実装例
Mediator
package main
type Mediator interface {
canRequest(IRequest) bool
notifyRequestFinished() // Component役からMediator役へ処理の完了を通知するためのメソッド。
}
Concrete Mediator
package main
// Mediatorインターフェースを実装する。
// リクエスト処理が同時に走らないように制御を行う。
type Manager struct {
isRequesting bool
queue []IRequest
}
func NewManger() *Manager {
return &Manager{}
}
func (m *Manager) canRequest(r IRequest) bool {
if m.isRequesting {
m.queue = append(m.queue, r)
return false
}
m.isRequesting = true
return true
}
// Componentからの処理完了通知用メソッド。
// キューから次にリクエストを送るComponentを取り出し、リクエスト処理の許可を与える。
func (m *Manager) notifyRequestFinished() {
if m.isRequesting {
m.isRequesting = false
}
if len(m.queue) > 0 {
firstQueue := m.queue[0]
m.queue = m.queue[1:]
firstQueue.permitSending()
}
}
Component
package main
type IRequest interface {
Send()
permitSending() // Mediatorからリクエスト許可をもらうためのメソッド
}
Concrete Component
package main
import (
"fmt"
"time"
)
type Request struct {
url string
mediator Mediator // Mediatorオブジェクトを保持する。
}
func NewRequest(url string, mediator Mediator) *Request {
return &Request{
url: url,
mediator: mediator,
}
}
func (r *Request) Send() {
if !r.mediator.canRequest(r) {
fmt.Printf("[url: %s] Another request is sending.\n", r.url)
return
}
fmt.Printf("[url: %s] Sending request.\n", r.url)
time.Sleep(time.Second * 1)
fmt.Printf("[url: %s] Sending request is finished.\n", r.url)
// 処理の完了をMediatorに通知する。
r.mediator.notifyRequestFinished()
}
func (r *Request) permitSending() {
fmt.Printf("[url: %s] Request sending is permitted.\n", r.url)
r.Send()
}
動作確認
package main
import (
"sync"
)
func main() {
urls := []string{
"https://www.yahoo.co.jp/",
"https://www.google.com/",
"https://github.com/",
}
var wg sync.WaitGroup
manager := NewManger()
request := func(url string) {
wg.Add(1)
defer wg.Done()
r := NewRequest(url, manager)
r.Send()
}
for _, url := range urls {
go request(url)
}
wg.Wait()
}
>> go run .
[url: https://github.com/] Sending request.
[url: https://www.google.com/] Another request is sending.
[url: https://www.yahoo.co.jp/] Another request is sending.
[url: https://github.com/] Sending request is finished.
[url: https://www.yahoo.co.jp/] Request sending is permitted.
[url: https://www.yahoo.co.jp/] Sending request.
[url: https://www.yahoo.co.jp/] Sending request is finished.
[url: https://www.google.com/] Request sending is permitted.
[url: https://www.google.com/] Sending request.
[url: https://www.google.com/] Sending request is finished.
コメント