外觀模式、橋接模式、狀態模式及其Go語言實現

1、外觀模式

(1)什麼是外觀模式?
外觀模式爲子系統中的一組接口提供了一個統一的訪問接口,這個接口使得子系統更容易被訪問或者使用。
外觀模式屬於結構型模式。外觀模式的本質是把一些複雜的流程封裝成一個接口供給外部用戶更簡單的使用。外觀模式最典型的代表就是MVC模式。M(Model):模型,處理應用程序數據邏輯的部分。V(View):視圖,處理數據顯示的部分。C(Controller):控制器,處理用戶交互的部分。
(2)生活場景實例
小明班級的英語試卷分爲聽力、選擇題、閱讀題、寫作題四個部分,英語考試的分數是四個部分分數總和。小明參加了班級的英語考試,聽力得分爲20分,選擇題得分爲42分,閱讀理解得分爲40分,寫作得分爲25分。

package main

import "fmt"

type EnglishTest interface {
	Listening() int
	Reading() int
	Selecting() int
	Writing() int
}
type student struct {
	name string
}
func (s *student) Listening(score int) int {
	fmt.Println(s.name, "聽力得分爲:", score)
	return score
}
func (s *student) Selecting(score int) int {
	fmt.Println(s.name, "選擇題得分爲:", score)
	return score
}
func (s *student) Reading(score int) int {
	fmt.Println(s.name, "閱讀理解得分爲:", score)
	return score
}
func (s *student) Writing(score int) int {
	fmt.Println(s.name, "寫作得分爲:", score)
	return score
}

func main() {
	s := &student{
		name : "小明",
	}
	totalScore := 0
	totalScore = totalScore + s.Listening(20)
	totalScore = totalScore + s.Selecting(42)
	totalScore = totalScore + s.Reading(40)
	totalScore = totalScore + s.Writing(25)
	fmt.Println(s.name, "的總得分爲", totalScore)
}

英語老師要統計班級所有同學的測驗分數。

package main

import "fmt"

type EnglishTest interface {
	Listening() int
	Reading() int
	Selecting() int
	Writing() int
}
type student struct {
	name string
}
func (s *student) listening(score int) int {
	fmt.Println(s.name, "聽力得分爲:", score)
	return score
}
func (s *student) selecting(score int) int {
	fmt.Println(s.name, "選擇題得分爲:", score)
	return score
}
func (s *student) reading(score int) int {
	fmt.Println(s.name, "閱讀理解得分爲:", score)
	return score
}
func (s *student) writing(score int) int {
	fmt.Println(s.name, "寫作得分爲:", score)
	return score
}
func (s *student) GetTotalScore() int {
	return s.listening(20) + s.selecting(42) + s.reading(40) + s.writing(25)
}

func main() {
	s := &student{
		name : "小明",
	}
	fmt.Println(s.name, "的總得分爲", s.GetTotalScore())
}

(3)外觀模式的特點
1)減少了系統的相互依賴。
2)提高了靈活性。不管系統內部如何變化,只要不影響到外觀對象,內部改動外部依賴無感知。
3)提高了安全性。只暴露外觀類中的方法,想讓你訪問子系統的哪些業務就開通哪些邏輯,不在外觀上開通的方法,你就訪問不到。
(4)真實使用場景
1)gin render
2)beego controller

2、橋接模式

(1)什麼是橋接模式?
橋接模式將抽象部分與它的實現部分分離,使它們都可以獨立地變化。
橋接模式其實是一種結構型模式,抽象與實現分離,這應該是我們學設計模式的一個基本思想。橋接模式無非就是合成複用原則的一個詮釋。
(2)生活場景實例
小明的學校一共有20個班級,現在學校需要舉辦班級風采大賽。每個班級都需要設計自己的班服,班服的顏色各班級自己定。

package main

type Class interface {
	Number() int
}
type Clothes interface {
	Color() string
}

type classOne struct {
	c Clothes						// 用類的組合,而不使用類的繼承,將班級和顏色分開
}
func (c *classOne) Number() int {
	return 1
}
type classTwo struct {
	c Clothes
}
func (c *classTwo) Number() int {
	return 2
}
type classThree struct {
	c Clothes
}
func (c *classThree) Number() int {
	return 3
}

type yellowClothes struct {}
func (y *yellowClothes) Color() string {
	return "黃色"
}
type whiteClothes struct {}
func (w *whiteClothes) Color() string {
	return "白色"
}

func wearClothes() {
	cla := &classOne{
		c : &yellowClothes{},		// 顏色在調用時具體化
	}
	fmt.Println("小明是", cla.Number(), "班的同學")
	fmt.Println("小明穿", cla.c.Color(), "的衣服")
}

func main() {
	wearClothes()
}

更優雅的橋接模式:

package main

type Class interface {
	Number() int
}
type Clothes interface {
	Color() string
}

type classOne struct {}
func (c *classOne) Number() int {
	return 1
}
type classTwo struct {}
func (c *classTwo) Number() int {
	return 2
}
type classThree struct {}
func (c *classThree) Number() int {
	return 3
}

type yellowClothes struct {}
func (y *yellowClothes) Color() string {
	return "黃色"
}
type whiteClothes struct {}
func (w *whiteClothes) Color() string {
	return "白色"
}

func wearClothes() {
	cla := &classOne{}
	clo := &whiteClothes{}				// 兩個接口沒有關聯,完全解耦
	fmt.Println("小明是", cla.Number(), "班的同學")
	fmt.Println("小明穿", clo.Color(), "的衣服")
}

func main() {
	wearClothes()
}

(3)橋接模式的特點
優點:組合比繼承更加靈活,分離了抽象和實現,提高了擴展性和靈活性。
缺點:增加了系統的理解與設計難度。
(4)真實使用場景
1)grpc dnsResolver
2)grpc TransportCredentials

3、狀態模式

(1)什麼是狀態模式?
狀態模式是指當一個對象的內在狀態改變時允許改變其行爲,使得這個對象看起來像是改變了其類。
狀態模式是一種行爲型模式,狀態模式主要解決的是當一個對象的狀態過於複雜時,把狀態的判斷邏輯轉移到不同狀態的一系列類中,可以把複雜的判斷邏輯簡單化。
(2)生活場景實例
小明的學校爲了方便學生的日常生活,在教學樓的每個樓層擺放了零食售貨機。這一天,小明來零食售貨機購買飲料。
零食售貨機的動作:插入硬幣、選擇商品、出貨、找零、退款。
零食售貨機的狀態:等待投幣、有硬幣、等待出貨、結算。

package main

import "fmt"

// 動作
type VendingMachine interface {
	// 插入硬幣
	InsertCoin(int)
	// 選擇商品
	ChooseGoods(int)
	// 出貨
	ShipGoods(int)
	// 結算
	Settlement(int)
}
type vendingMachine struct {}
type goods struct {
	state int
}

func (v *vendingMachine) InsertCoin(state int) {
	switch v.state {
		case WaitingForCoin:
			fmt.Println("插入硬幣成功...")
			v.state =  HasCoin
			break
		case HasCoin:
			fmt.Println("售貨機已經有硬幣,請等待...")
			break
		case WaitingForShipGoods:
			fmt.Println("商品選擇中,請等待購買完成之後再投幣...")
			break
		case Refund:
			fmt.Println("結算中,請耐心等待...")
			break
		case FreeGoods:
			fmt.Println("免費水果,無需硬幣購買...")
			break
	}
}
func (v *vendingMachine) ChooseGoods(state int) {
	switch v.state {
		case WaitingForCoin:
			fmt.Println("請先插入硬幣...")
			break
		case HasCoin:
			fmt.Println("選擇商品完成...")
			v.state = WaitingForShipGoods
			break
		case WaitingForShipGoods:
			fmt.Println("請耐心等待商品出貨...")
			break
		case Refund:
			fmt.Println("結算中,請耐心等待...")
			break
		case FreeGoods:
			fmt.Println("免費水果,每人只能選擇一份哦...")
			break
	}
}
func (v *vendingMachine) ShipGoods() {
	switch v.state {
		case WaitingForCoin:
			fmt.Println("請先插入硬幣...")
			break
		case HasCoin:
			fmt.Println("請先選擇商品...")
			break
		case WaitingForShipGoods:
			fmt.Println("出貨中,請耐心等待...")
			v.state = Refund
			break
		case Refund:
			fmt.Println("結算中,請耐心等待結算完成再操作...")
			break
		case FreeGoods:
			fmt.Println("免費水果正在出貨...")
			break
	}
}
func (v *vendingMachine) Settlement() {
	switch v.state {
		case WaitingForCoin:
			fmt.Println("請先插入硬幣...")
			break
		case HasCoin:
			fmt.Println("請先選擇商品...")
			break
		case WaitingForShipGoods:
			fmt.Println("請耐心等待商品出貨...")
			break
		case Refund:
			fmt.Println("結算完成,請拿走您的商品...")
			v.state = WaitingForCoin
			break
		case FreeGoods:
			fmt.Println("免費水果,無需結算,請拿走您的水果...")
			break
	}
}

// 狀態
// 等待投幣
const WaitingForCoin = 1
// 有硬幣
const HasCoin = 2
// 等待出貨
const WaitingForShipGoods = 3
// 結算
const Refund = 4

func buyGoods() {
	g := &goods{
		state : WaitingForCoin,
	}
	v := &vendingMachine{}
	v.InsertCoin()
	v.ChooseGoods()
	v.ShipGoods()
	v.Settlement()
}

func main() {
	buyGoods()
}

因爲學生家長的捐贈,同時爲了學生身體健康,學校決定在零食售貨機裏面每天投放一些水果,這些水果是免費的。則增加一個免費水果的狀態,不使用狀態模式設計思想如上述代碼,使用狀態模式設計思想將狀態作爲一個接口,將每一個狀態擁有者四個動作,這樣增加一個免費水果的狀態就滿足開閉原則。

type State interface {
	// 插入硬幣
	InsertCoin()
	// 選擇商品
	ChooseGoods()
	// 出貨
	ShipGoods()
	// 結算
	Settlement()
}

(3)狀態模式的特點
1)對象的動作和對象的狀態是相對的,明確變與不變,狀態模式變的是狀態。
2)提高了類的擴展性,可以在不破壞開閉原則的基礎上增加新的狀態。
3)狀態過多可能導致類膨脹,結構與實現都較爲複雜。
(4)Go Context中的應用

type Context interface {
	Deadline() (deadline time.Time, ok bool)
	Done() <-chan struct {}
	Err() error
	Value(key interface{}) interface{}
}
發佈了238 篇原創文章 · 獲贊 620 · 訪問量 132萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章