设计模式之装饰器模式

一、装饰器模式介绍

装饰器模式(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中,文件流也使用了类似模式,大家可有空可以去看看代码。

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

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

相关推荐
_GR12 分钟前
每日OJ题_牛客_牛牛冲钻五_模拟_C++_Java
java·数据结构·c++·算法·动态规划
无限大.25 分钟前
c语言200例 067
java·c语言·开发语言
余炜yw26 分钟前
【Java序列化器】Java 中常用序列化器的探索与实践
java·开发语言
攸攸太上26 分钟前
JMeter学习
java·后端·学习·jmeter·微服务
Kenny.志29 分钟前
2、Spring Boot 3.x 集成 Feign
java·spring boot·后端
不修×蝙蝠32 分钟前
八大排序--01冒泡排序
java
sky丶Mamba1 小时前
Spring Boot中获取application.yml中属性的几种方式
java·spring boot·后端
数据龙傲天1 小时前
1688商品API接口:电商数据自动化的新引擎
java·大数据·sql·mysql
刷帅耍帅1 小时前
设计模式-桥接模式
设计模式·桥接模式
带带老表学爬虫2 小时前
java数据类型转换和注释
java·开发语言