Chain of Responsibility,將實作透過串串樂串起來

什麼是 Chain of Responsibility?

將 if…else 的行為抽象成物件,將 if…else 行為以物件串接的方式來操作

問題情境

在 PS5 的設計中,假設會依照不同的遊戲調整晶片,例如 3D 遊戲會啟用 3D 模式、高效能顯示會加強顯示晶片、音樂有用環繞音效會啟用音效晶片的環繞音效模式,

會設計成以下的 code:

package main

import "fmt"

type Game struct {
	Name      string
	Type      string
	GraphType string
	AudioType string
}

type PS5 struct{}

func (PS5) PlayGame(game Game) {
	if game.Type == "3D遊戲" {
		fmt.Println("3D模式")
	}
	if game.GraphType == "高效能顯示" {
		fmt.Println("加強顯示晶片")
	}
	if game.AudioType == "環繞音效" {
		fmt.Println("環繞音效模式")
	}
	fmt.Printf("play %s", game.Name)
}

func main() {
	ps5 := PS5{}
	ps5.PlayGame(
		Game{
			Name:      "最終幻想",
			Type:      "3D遊戲",
			GraphType: "高效能顯示",
			AudioType: "環繞音效",
		},
	)
}

如果要在新增不同的晶片調整,就必須修改PS5{}.PlayGame()的 code,這不符合開閉原則,我們需要一個方式解決。

解決方式

可以在PS5{}新增一個middleware slice 成員,並把調整晶片的邏輯都抽象成GameMiddleware()GraphMiddleware()AudioMiddleware()middlewares,透過PS5{}.AddMiddleware()來新增這些 middleware,在最後PS5{}.PlayGame()的時候再一次運行所有 middleware 並且運行遊戲

package main

import "fmt"

type Game struct {
	Name      string
	Type      string
	GraphType string
	AudioType string
}

type PS5 struct {
	middlewares []func(game Game)
}

func (p *PS5) AddMiddleware(middleware func(game Game)) *PS5 {
	p.middlewares = append(p.middlewares, middleware)
	return p
}

func (p PS5) PlayGame(game Game) {
	for _, middleware := range p.middlewares {
		middleware(game)
	}
	fmt.Printf("play %s", game.Name)
}

func GameMiddleware(game Game) {
	if game.Type == "3D遊戲" {
		fmt.Println("3D模式")
	}
}

func GraphMiddleware(game Game) {
	if game.GraphType == "高效能顯示" {
		fmt.Println("加強顯示晶片")
	}
}

func AudioMiddleware(game Game) {
	if game.AudioType == "環繞音效" {
		fmt.Println("環繞音效模式")
	}
}

func main() {
	ps5 := PS5{}
	ps5.
		AddMiddleware(GameMiddleware).
		AddMiddleware(GraphMiddleware).
		AddMiddleware(AudioMiddleware)
	ps5.PlayGame(
		Game{
			Name:      "最終幻想",
			Type:      "3D遊戲",
			GraphType: "高效能顯示",
			AudioType: "環繞音效",
		},
	)
}
comments powered by Disqus