func main() {
e := &Espresso{}
m := NewMocha(e)
s := NewSoy(m)
fmt.Println(s.Desc(), "=", s.Cost())
h := &HouseBlend{}
w := NewWhip(h)
fmt.Println(w.Desc(), "=", w.Cost())
}
output:
➜ decorator go run main.go
Espresso + Mocha + Soy = 2.3
HouseBlend + Whip = 2.2
所有的设计模式和架构设计都是解决软件规模变大之后的问题, 这也是看装饰器模式这一章之后的第一感觉。在小的项目中确实可以不用做过多的设计,一个简单的继承基本上都能搞定,比如这样 当项目变大变复杂之后会变成什么样?无限制的扩展吗? 像这样:
所谓模式就是前人总结的经验,在工程上你目前遇到的问题,你肯定不是第一个遇到,所有寻找业界的做的是很关键的,可以看看那些成熟的项目是如何处理的。
这里与其叫装饰器模式,不如叫 wrap模式, 这样更形象一些,不断的在基础功能上套附加功能。这里的关键是提供方只提供了基础的被装饰类和装饰类(各个类之间又遵循一种原则),然后怎样装饰一个类完全交给使用方,这样可以避免在提供方进行层次的继承,这里也体现了设计中 组合优于继承 的原则。另外在新增被装饰类和装饰类时也不用修改老的代码,也符合 开闭原则。
比如下面的类结构中: 如果我们要计算““double mocha soy latte with whip” beverage” 的cost的时候就可以按照下面剥洋葱式的计算方式:
下面我们就用golang来实现上面的类结构:
使用方在基本款的基础上任意组合:
output:
Decorator in real world
装饰器模式的核心是将一个类的功能附加在另外一个类的功能之上,但这里完全不要被面向对象中的class给迷惑,在golang中完全可以使用高阶函数来实现装饰器模式,且看http中的middlewaer模式。这也是好多框架实现的模式,在http请求进来之后做一系列的action(鉴权/审计)等等。
这里就是一个装饰器模式,在被装饰类 HelloHandler 上不断的附加middleware功能。