设计模式之装饰器模式

一、装饰器模式介绍

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

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

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

相关推荐
songbaoxian8 分钟前
ElasticSearch
java·linux·elasticsearch
非 白22 分钟前
【Java】代理模式
java·开发语言·代理模式
Good Note33 分钟前
Golang的静态强类型、编译型、并发型
java·数据库·redis·后端·mysql·面试·golang
我就是我3521 小时前
记录一次SpringMVC的406错误
java·后端·springmvc
向哆哆1 小时前
Java应用程序的跨平台性能优化研究
java·开发语言·性能优化
ekkcole2 小时前
windows使用命令解压jar包,替换里面的文件。并重新打包成jar包,解决Failed to get nested archive for entry
java·windows·jar
handsomestWei2 小时前
java实现多图合成mp4和视频附件下载
java·开发语言·音视频·wutool·图片合成视频·视频附件下载
全栈若城2 小时前
03 Python字符串与基础操作详解
java·开发语言·python
伯牙碎琴3 小时前
二、Spring Framework基础:IoC(控制反转)和DI(依赖注入)
java·spring·log4j
菲力蒲LY3 小时前
输入搜索、分组展示选项、下拉选取,全局跳转页,el-select 实现 —— 后端数据处理代码,抛砖引玉展思路
java·前端·mybatis