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{}
}