我们每天早上起来都需要穿衣服,我们穿衣服的过程就是装饰自己的过程,而且我们可能每次穿衣服的顺序也不一样,比如有一天张三起床,他首先穿上红内裤,然后再穿上花裤衩,然后再穿上大码衬衫,然后穿上西装,然后就出门了;又有一天张三起床,首先穿上西裤,然后穿上红内裤,然后穿上花短袖,然后穿上棉服就出门了。在这个过程中,我们发现张三穿衣服的顺序以及衣服款式都是不固定的,非常灵活,想穿什么穿什么。
既然穿衣可以这么灵活多变,那我们在软件设计中可不可以也这么灵活多变呢?答案是肯定的。也就是下面我们要讲的装饰模式。
1 定义
装饰模式(Decorator): 动态的给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更为灵活
我们对比一下建造者模式,建造者模式要求建造的过程必须是稳定的,也就是我们必须经过A–>B–>C道工序,才能生产出产品P。但是装饰模式的建造过程是不稳定的,我们可以经过A–>B–>C生产出P,也可以经过C–>B–>A生产出P,还可以B–>A–>C生产出P等等等等。。。。
UML类图:
由于go里面没有继承的概念,所以可以将上面类图中红色框中的interface去掉。
几个重要的角色:
- Component(抽象构建):具体构建和抽象装饰类的基类,声明了在具体构建中实现的业务方法,UML类图中的Component
- ConcreteComponent(具体构建):抽象构建的子类,用于定义具体的构建对象,实现了在抽象构建中声明的方法,装饰器可以给它增加额外的职责(方法),UML类图中的Window、TextBox、ListBox
- Decorator(抽象装饰类):也是抽象构建类的子类,用于给具体构建增加职责,但是具体职责在其子类中实现,UML类图中的ComponentDecorator
- ConcreteDecorator(具体装饰类):抽象装饰类的子类,负责向构建添加新的职责,UML类图中的ScrollBarDecorator、BlackBorderDecorator
2 go语言实现
2.1 实现Component抽象类以及ConcreteComponent具体构建
type Component interface {
Display()
}
type Window struct{}
func (w Window) Display() {
fmt.Println("显示窗体")
}
type TextBox struct{}
func (t TextBox) Display() {
fmt.Println("显示文本框")
}
type ListBox struct{}
func (l ListBox) Display() {
fmt.Println("显示列表框")
}
2.2 实现ConcretDecorator具体装饰类
type ScrollBarDecorator struct {
Component
}
func (sbd ScrollBarDecorator) Display() {
fmt.Println("为构建增加滚动条")
sbd.Component.Display()
}
type BlackBorderDecorator struct {
Component
}
func (bbd BlackBorderDecorator) Display() {
fmt.Println("为构建增加黑色边框")
bbd.Component.Display()
}
2.3 定义工厂函数生产出具体装饰类
func NewDecorator(t string, decorator Component) Component {
switch t {
case "sbd":
return ScrollBarDecorator{
Component: decorator,
}
case "bbd":
return BlackBorderDecorator{
Component: decorator,
}
default:
return nil
}
}
2.4 测试demo
func main() {
component := decorator.Window{}
tScrollBarDecorator := decorator.NewDecorator("sbd", component)
tScrollBarDecorator.Display()
fmt.Println("==============================")
tBlackBorderDecorator := decorator.NewDecorator("bbd", tScrollBarDecorator)
tBlackBorderDecorator.Display()
}