文章目录
- 一、简介
- 二、基本概念
- 三、装饰模式的结构和实现
- 类图解析:
- 装饰器的实现方式
- 继承实现:
- 组合实现:
- 继承和组合对比
- 四、装饰模式的应用场景
- 五、与其他模式的关系
- 六、总结
一、简介
装饰模式是一种结构型设计模式,它允许动态地向对象添加额外的功能。
二、基本概念
- 装饰模式定义:在不改变原有对象结构的情况下,通过对其进行包装拓展,以达到增强功能的目的。
- 装饰器角色:负责给组件对象附加额外的功能,实现了与组件具有相同接口的装饰器类。
- 组件角色:拥有核心功能的原始对象。
- 抽象组件角色:定义了组件对象的接口,可以是抽象类或接口。
- 具体组件角色:实现了抽象组件角色的具体对象。
三、装饰模式的结构和实现
类图解析:
// 抽象组件角色
public interface Component {
void operation();
}
// 具体组件角色
public class ConcreteComponent implements Component {
public void operation() {
// 实现核心功能
System.out.println("这是具体组件角色的核心功能");
}
}
// 装饰器角色
public abstract class Decorator implements Component {
protected Component component;
public Decorator(Component component) {
this.component = component;
}
public void operation() {
component.operation();
}
}
// 具体装饰器角色
public class ConcreteDecorator extends Decorator {
public ConcreteDecorator(Component component) {
super(component);
}
public void operation() {
// 添加额外功能代码
System.out.println("具体装饰器角色:"+"执行核心组件的功能前111");
super.operation();
// 添加额外功能代码
System.out.println("具体装饰器角色:"+"执行核心组件的功能后2222");
}
}
- 客户端代码示例:
Component component = new ConcreteComponent(); // 创建具体组件对象
component.operation(); // 调用核心功能
Component decoratedComponent = new ConcreteDecorator(component); // 使用具体装饰器装饰组件
decoratedComponent.operation(); // 调用增强功能
装饰器的实现方式
继承实现:
具体装饰器继承装饰器抽象类,通过重写父类方法实现功能拓展
- 继承实现方式:
// 抽象组件角色
interface Component {
void operation();
}
// 具体组件角色
class ConcreteComponent implements Component {
public void operation() {
// 执行核心功能
System.out.println("执行核心功能");
}
}
// 抽象装饰器角色
abstract class Decorator implements Component {
protected Component component;
public Decorator(Component component) {
this.component = component;
}
public void operation() {
component.operation();
}
}
// 具体装饰器角色
class ConcreteDecoratorA extends Decorator {
public ConcreteDecoratorA(Component component) {
super(component);
}
public void operation() {
super.operation();
// 添加额外的功能代码
System.out.println("添加额外的功能代码A");
}
}
class ConcreteDecoratorB extends Decorator {
public ConcreteDecoratorB(Component component) {
super(component);
}
public void operation() {
super.operation();
// 添加额外的功能代码
System.out.println("添加额外的功能代码B");
}
}
// 使用示例
public class Main {
public static void main(String[] args) {
// 创建具体组件对象
Component component = new ConcreteComponent();
// 创建具体装饰器对象,并包装组件对象
Component decoratorA = new ConcreteDecoratorA(component);
Component decoratorB = new ConcreteDecoratorB(decoratorA);
// 调用装饰器的操作方法,实现功能的拓展
decoratorB.operation();
}
}
组合实现:
具体装饰器持有装饰器抽象类的实例,通过调用实例方法实现功能拓展。
2. 组合实现方式:
// 抽象组件角色
interface Component {
void operation();
}
// 具体组件角色
class ConcreteComponent implements Component {
public void operation() {
// 执行核心功能
System.out.println("执行核心功能");
}
}
// 装饰器角色
class Decorator implements Component {
protected Component component;
public Decorator(Component component) {
this.component = component;
}
public void operation() {
component.operation();
}
}
// 具体装饰器角色
class ConcreteDecoratorA extends Decorator {
public ConcreteDecoratorA(Component component) {
super(component);
}
public void operation() {
super.operation();
// 添加额外的功能代码
System.out.println("添加额外的功能代码A");
}
}
class ConcreteDecoratorB extends Decorator {
public ConcreteDecoratorB(Component component) {
super(component);
}
public void operation() {
super.operation();
// 添加额外的功能代码
System.out.println("添加额外的功能代码B");
}
}
// 使用示例
public class Main {
public static void main(String[] args) {
// 创建具体组件对象
Component component = new ConcreteComponent();
// 创建具体装饰器对象,并包装组件对象
Component decoratorA = new ConcreteDecoratorA(component);
Component decoratorB = new ConcreteDecoratorB(decoratorA);
// 调用装饰器的操作方法,实现功能的拓展
decoratorB.operation();
}
}
这两个示例中,都有一个抽象的组件角色(Component
),一个具体的组件角色(ConcreteComponent
),以及几个具体的装饰器角色(ConcreteDecorator
)。具体装饰器角色在构造函数中接收一个组件对象,并在自身的 operation()
方法中调用组件对象的 operation()
方法,并添加额外的功能代码。
在使用示例中,我们创建了具体组件对象和具体装饰器对象,并将它们进行组合,最后调用装饰器的 operation()
方法来实现功能的拓展。
继承和组合对比
在装饰器模式中,继承实现和组合实现是两种常见的方式。它们在实现装饰器功能时略有不同:
继承实现:
- 优点:
- 简单直接:通过继承抽象装饰器类,具体装饰器可以直接重写方法并添加额外功能。
- 可复用性高:可以轻松地创建多个具体装饰器,并进行组合拓展。
- 缺点:
- 类爆炸:每个具体装饰器都需要创建一个新的类,当装饰器数量增多时,类的数量也会大量增加。
- 静态结构:类的组合和功能拓展是在编译时静态决定的,无法动态地改变组合方式。
组合实现:
- 优点:
- 灵活组合:具体装饰器持有抽象装饰器对象,可以在运行时动态地组合不同的装饰器对象,实现不同的功能拓展组合。
- 类结构简单:相对于继承实现,不需要创建过多的具体装饰器类,类结构相对简单。
- 缺点:
- 代码复杂度较高:需要在具体装饰器中额外处理抽象装饰器对象的方法调用。可能需要在抽象装饰器中定义一些默认实现,以避免空指针异常。
根据具体需求和设计考虑,可以选择适合的实现方式。继承实现适用于静态且数量有限的装饰器组合,而组合实现适用于动态和灵活的装饰器组合。两种实现方式都能实现装饰器模式的基本功能,只是在代码结构和使用方式上略有差异。
四、装饰模式的应用场景
- 动态添加功能:当需要在不修改现有代码的情况下,动态地给对象添加新功能时,装饰模式可以很好地满足这一需求。
- 避免子类爆炸:利用装饰模式,可以避免通过创建大量子类来实现各种功能组合的问题。
- 透明性 vs. 安全性:装饰模式中的装饰器和组件具有相同的接口,使得对于客户端而言,无需关心具体是使用了原始组件还是装饰器对象,实现了透明性。
五、与其他模式的关系
- 装饰模式 vs. 适配器模式:装饰模式侧重于给对象动态添加功能,而适配器模式则是为了让不兼容的类能够协同工作。
- 装饰模式 vs. 组合模式:装饰模式和组合模式都采用了递归组合的思想,但装饰模式着重于给对象添加功能,而组合模式着重于构建对象的树形结构。
- 装饰模式 vs. 桥接模式:桥接模式将抽象部分和实现部分解耦,而装饰模式则是在不改变对象结构的基础上,拓展其功能。
六、总结
装饰模式通过包装对象实现功能的动态拓展,使得系统具有更高的灵活性和可扩展性。它应用广泛,在动态添加功能、避免子类爆炸等场景都很有价值。同时,要注意使用装饰模式时,保持透明性和安全性的平衡,确保装饰器和组件具有一致的接口。