设计模式之装饰器模式

一、装饰器模式介绍

装饰器模式(Decorator Pattern),也被称为包装器模式(Wrapper Pattern),是一种结构型设计模式,主要用于在不改变原有对象结构的基础上,动态地给对象增加一些额外的职责或功能。这种模式提供了一种比使用继承更加灵活的替代方案,使得对象的功能扩展变得更加容易和灵活。

1、装饰器模式类图及主要角色

观察者模式类图:

装饰器模式主要包含以下几个角色:

  1. 抽象构件(Component):定义一个对象接口,可以给这些对象动态地添加一些职责。
  2. 具体构件(Concrete Component):定义了一个具体的对象,也可以给这个对象添加一些职责。
  3. 抽象装饰器(Decorator):持有一个构件(Component)对象的引用,并定义一个与抽象构件一致的接口。
  4. 具体装饰器(Concrete Decorator):负责给构件对象"贴上"附加的职责。

2、应用场景

装饰器模式通常适用于以下场景:

  1. 动态地给对象添加额外的职责:装饰器模式允许在运行时动态地将新功能附加到对象上,而不需要修改现有的类代码。
  2. 扩展功能更加灵活:相比于继承,装饰器模式提供了更灵活的扩展方式,避免了类的爆炸性增长。
  3. 符合开闭原则:装饰器模式可以在不修改现有代码的情况下引入新的装饰器类,从而扩展系统功能。
  4. 透明地给单个对象添加职责:装饰器模式可以透明地给对象添加职责,而不会影响到其他对象。

3、优缺点

优点

  1. 装饰类和被装饰类可以独立发展:装饰器模式使得装饰类和被装饰类可以独立变化,不会相互耦合。
  2. 动态扩展功能:装饰器模式允许动态地扩展一个实现类的功能,而无需修改现有代码。
  3. 灵活性高:多个装饰器可以被组合使用,从而创建不同的组合效果,使得系统具有更大的灵活性。

缺点

  1. 多层装饰比较复杂:随着装饰器的增多,类的数量也会增加,使得代码变得复杂和难以维护。
  2. 性能开销:如果过多装饰器嵌套,可能会引入一定的性能开销。

二、实现示例

下面是一个使用Java实现的装饰器模式示例,用于动态地给咖啡添加不同的调料(如糖、牛奶等),而无需为每个调料组合创建一个新的咖啡子类。

首先,我们定义一个咖啡的抽象类(Component):

java 复制代码
// 咖啡抽象类  
public abstract class Coffee {  
    String description = "Unknown Coffee";  
  
    public String getDescription() {  
        return description;  
    }  
  
    public abstract double cost();  
}

然后,我们创建一个具体的咖啡类(Concrete Component):

java 复制代码
// 具体咖啡类:浓缩咖啡  
public class Espresso extends Coffee {  
    public Espresso() {  
        description = "Espresso";  
    }  
  
    @Override  
    public double cost() {  
        return 1.99;  
    }  
}

接下来,我们创建一个装饰器的抽象类(Decorator):

java 复制代码
// 咖啡装饰器抽象类  
public abstract class CoffeeDecorator extends Coffee {  
    public abstract String getDescription();  
}

现在,我们可以创建具体的装饰器类了,比如加糖(Concrete Decorator):

java 复制代码
// 具体装饰器:加糖  
public class WithSugar extends CoffeeDecorator {  
    Coffee coffee;  
  
    public WithSugar(Coffee c) {  
        this.coffee = c;  
    }  
  
    @Override  
    public String getDescription() {  
        return coffee.getDescription() + ", with sugar";  
    }  
  
    @Override  
    public double cost() {  
        return .10 + coffee.cost();  
    }  
}

再创建一个加牛奶的装饰器(Concrete Decorator):

java 复制代码
// 具体装饰器:加牛奶  
public class WithMilk extends CoffeeDecorator {  
    Coffee coffee;  
  
    public WithMilk(Coffee c) {  
        this.coffee = c;  
    }  
  
    @Override  
    public String getDescription() {  
        return coffee.getDescription() + ", with milk";  
    }  
  
    @Override  
    public double cost() {  
        return .20 + coffee.cost();  
    }  
}

最后,我们可以编写一个测试类来演示装饰器模式的使用:

java 复制代码
public class DecoratorPatternDemo {  
    public static void main(String args[]) {  
        Coffee espresso = new Espresso();  
        System.out.println(espresso.getDescription()   
            + " $" + espresso.cost());  
  
        Coffee darkRoast = new Espresso();  
        darkRoast = new WithMilk(darkRoast);  
        darkRoast = new WithSugar(darkRoast);  
        System.out.println(darkRoast.getDescription()   
            + " $" + darkRoast.cost());  
    }  
}

在这个示例中,我们首先创建了一个浓缩咖啡对象,并打印了它的描述和价格。然后,我们创建了一个浓缩咖啡对象,并动态地给它添加了牛奶和糖两种调料,最后打印了加调料后的咖啡描述和价格。这样,我们就可以在不修改现有咖啡类的情况下,通过装饰器模式动态地给咖啡添加不同的调料了。这个设计模式有点像**俄罗斯套娃,一层层套起来,在行为组合方面,有很好的灵活性,**我们JDK中,文件流也使用了类似模式,大家可有空可以去看看代码。

综上所述,装饰器模式是一种非常有用的设计模式,它提供了一种灵活的方式来扩展对象的功能,同时避免了类的爆炸性增长(其实类的爆炸是转移到了装饰器了)和代码的耦合。

如果对你有用,记得点赞加收藏哦!

相关推荐
君顾116 分钟前
智慧零售实战指南:从技术架构到落地方案全解析
java·开发语言·零售
zhanghe6871 小时前
es的密码带有特殊字符,导出
java
pnoker1 小时前
IoT DC3 概念解读:把设备抽象成一套语义模板——位号、指令、事件与面向智能体的设备建模
java·人工智能·物联网·iot·dc3
my_realmy1 小时前
Java SE 基础学习笔记(一):面向对象、继承多态、抽象接口与异常(JDK 8)
java·多线程·并发··生产者消费者模式
天远数科2 小时前
风险治理实战:基于天远车信盟出险构建自动化理赔核保流水线
java·网络·人工智能·自动化
骇客野人2 小时前
SpringBoot电商系统用户注册、登录、留存及数据埋点设计与落地实施方案
java·spring boot·后端
qiuhaipeng12 小时前
Claude code 升级后上下文长度变短问题
java·前端·数据库
wxwx_bscxy3223 小时前
基于Python新冠疫情可视化分析系统的设计与实现
java·数据库·spring boot·python·微信小程序·sqlite
evans在进步4 小时前
Tomcat NIO 工作原理详解:从 Acceptor、Poller 到容器处理链
java·tomcat·nio
渡我白衣5 小时前
并查集:基础认识与模拟实现
android·java·javascript·数据结构·c++·算法·并查集