装饰器模式(Decorator Pattern)是一种结构型设计模式,它允许向一个现有的对象添加新的功能,同时又不改变其结构。这种模式创建了一个装饰类,用来包装原有的类,并在保持原类方法签名完整性的前提下,提供了额外的功能。
装饰器模式的主要组成
- Component(组件):定义了对象的接口,可以给这些对象动态地添加职责。
- Concrete Component(具体组件):定义了对象的一个具体实现。
- Decorator(装饰器):持有一个组件对象的引用,并实现与组件相同的接口。
- Concrete Decorator(具体装饰器):负责给组件添加新的功能。
装饰器模式的实现步骤
- 定义组件接口:这个接口规定了可以装饰的对象的类型。
- 创建具体组件:实现组件接口,定义一个具体的对象。
- 创建装饰器抽象类:实现组件接口,并持有一个组件对象的引用。
- 创建具体装饰器:继承装饰器抽象类,实现具体装饰逻辑。
装饰器模式的优点
- 扩展性:可以在不修改原有对象代码的前提下,通过添加新的装饰器来扩展功能。
- 灵活性:可以在运行时动态地添加或去除职责。
- 低耦合性:装饰器和具体组件之间是松耦合的,增加新的装饰器不需要修改组件代码。
装饰器模式的缺点
- 过度使用:如果过度使用装饰器模式,可能会导致系统变得复杂,难以理解。
- 性能问题:装饰器可能会增加一些性能开销,因为每次装饰都涉及到额外的对象创建和方法调用。
装饰器模式的使用场景
- 当需要在不修改对象源代码的情况下,给对象添加新的功能时。
- 当需要动态地给一个对象添加功能时,这些功能可以是临时的。
package main
import "fmt"
// Component 定义了对象的接口,可以给这些对象动态地添加职责
type Component interface {
Operation() string
}
// ConcreteComponent 定义了对象的一个具体实现
type ConcreteComponent struct{}
func (c *ConcreteComponent) Operation() string {
return "ConcreteComponent"
}
// Decorator 持有一个Component对象的引用,并实现与Component相同的接口
type Decorator struct {
Component Component
}
func (d *Decorator) Operation() string {
return d.Component.Operation()
}
// ConcreteDecorator 负责给Component添加新的功能
type ConcreteDecoratorA struct {
Decorator
}
func (cda *ConcreteDecoratorA) Operation() string {
return cda.Decorator.Operation() + " ConcreteDecoratorA"
}
// ConcreteDecoratorB 另一个装饰器,添加不同的功能
type ConcreteDecoratorB struct {
Decorator
}
func (cdb *ConcreteDecoratorB) Operation() string {
return cdb.Decorator.Operation() + " ConcreteDecoratorB"
}
func main() {
// 创建具体组件
component := &ConcreteComponent{}
// 动态添加装饰器
decoratorA := &ConcreteDecoratorA{Decorator{Component: component}}
decoratorB := &ConcreteDecoratorB{Decorator: Decorator{Component: decoratorA}}
// 输出装饰后的结果
fmt.Println(component.Operation()) // 输出 ConcreteComponent
fmt.Println(decoratorA.Operation()) // 输出 ConcreteComponent ConcreteDecoratorA
fmt.Println(decoratorB.Operation()) // 输出 ConcreteComponent ConcreteDecoratorA ConcreteDecoratorB
}
装饰器模式主要用于解决继承关系过于复杂的问题,通过组合来替代继承,主要作用是给原始类添加增加功能。
实现方式是继承或接口,如果装饰类的方法大部分和原类相同,用继承。
和代理模式的区别:代码形式上几乎没有区别。代码模式主要是给原始类添加无关的功能,装饰器模式主要是给原始类增强功能,添加的功能都是有关联的。