装饰器模式:不改变原对象的基础上,灵活地给对象添加额外职责。装饰器相比于生成子类更加灵活。即将实现同一接口的父类当做参数传入包装器对象,动态创建出新的对象。
给对象添加新行为最简单直观的办法就是扩展本体对象,通过继承的方式达到目的。但使用继承有两个弊端:
使用装饰器模式,我们通过将现有对象放置在实现了相同一套接口的包装器对象中来动态地向现有对象添加新行为。在包装器中进行我们代码的扩展,有助于重用功能并且不会修改现有对象的代码,符合“开闭原则”。
装饰器模式中主要有如下几个角色:
Operation
方法中调用被装饰对象的Operation
方法Operation
方法实现增强逻辑。类图里已经给出了要实现的主要逻辑,第四步的基础装饰类并不需要一定存在,完全可以由具体装饰类来持有对被装饰对象的引用,并实现增强逻辑,这样一来整体的结构会更简单一些。去掉基础装饰类就是代理模式
定义一个游戏主机的产品接口,它就是上面类图中组件和装饰器的公共接口。
// PS5 产品接口
type PS5 interface {
StartGPUEngine()
GetPrice() int64
}
提供一个基础的产品实现类作为装饰器模式中的组件
// CD 版 PS5主机
type PS5WithCD struct{}
func (p PS5WithCD) StartGPUEngine() {
fmt.Println("start engine")
}
func (p PS5WithCD) GetPrice() int64 {
return 5000
}
提供一个数字版游戏主机的实现作为组件实现类。
// PS5 数字版主机
type PS5WithDigital struct{}
func (p PS5WithDigital) StartGPUEngine() {
fmt.Println("start normal gpu engine")
}
func (p PS5WithDigital) GetPrice() int64 {
return 3600
}
用两个装饰器实现的Plus版和主题配色版的两个增强。
// Plus 版的装饰器
func (p *PS5MachinePlus) SetPS5Machine(ps5 PS5) {
p.ps5Machine = ps5
}
func (p PS5MachinePlus) StartGPUEngine() {
p.ps5Machine.StartGPUEngine()
fmt.Println("start plus plugin")
}
func (p PS5MachinePlus) GetPrice() int64 {
return p.ps5Machine.GetPrice() + 500
}
// 主题色版的装饰器
type PS5WithTopicColor struct {
ps5Machine PS5
}
func (p *PS5WithTopicColor) SetPS5Machine(ps5 PS5) {
p.ps5Machine = ps5
}
func (p PS5WithTopicColor) StartGPUEngine() {
p.ps5Machine.StartGPUEngine()
fmt.Println("尊贵的主题色主机,GPU启动")
}
func (p PS5WithTopicColor) GetPrice() int64 {
return p.ps5Machine.GetPrice() + 200
}
两个增强还可以叠加在一起,组合出即高配主题限定版主机.
func main() {
ps5MachinePlus := PS5MachinePlus{}
ps5MachinePlus.SetPS5Machine(PS5WithCD{})
// ps5MachinePlus.SetPS5Machine(PS5WithDigital{}) // 可以在更换主机
ps5MachinePlus.StartGPUEngine()
price := ps5MachinePlus.GetPrice()
fmt.Printf("PS5 CD 豪华Plus版,价格: %d 元\n\n", price)
ps5WithTopicColor := PS5WithTopicColor{}
ps5WithTopicColor.SetPS5Machine(ps5MachinePlus)
ps5WithTopicColor.StartGPUEngine()
price = ps5WithTopicColor.GetPrice()
fmt.Printf("PS5 CD 豪华Plus 经典主题配色版,价格: %d 元\n", price)
}
装饰器和代理在结构上类似,在行为上跟职责链模式类似
但装饰器的使用必将会给程序带来更高的复杂性,更低的可读性,子类集成的代码结构会更直白易懂一些,而且虽然装饰器符合“开闭原则”,但是它会给程序带来更多的类,动态装饰在多层装饰时会更复杂,对于大型项目来说也是更好维护,我最近写一个项目就是,实现原型后要对基础Entry类进行更加具体的拓展,这无疑要对代码进行重构,后续可能进一步升级项目功能,那就需要不断重构,使用装饰器模式可以使代码健壮性良好,有利于进一步维护。
参考公众号网管叨bi叨