设计模式之装饰器模式

一、装饰器模式介绍

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

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

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

相关推荐
诸葛悠闲25 分钟前
设计模式——桥接模式
设计模式·桥接模式
Yan.love35 分钟前
开发场景中Java 集合的最佳选择
java·数据结构·链表
椰椰椰耶38 分钟前
【文档搜索引擎】搜索模块的完整实现
java·搜索引擎
大G哥38 分钟前
java提高正则处理效率
java·开发语言
智慧老师1 小时前
Spring基础分析13-Spring Security框架
java·后端·spring
lxyzcm1 小时前
C++23新特性解析:[[assume]]属性
java·c++·spring boot·c++23
V+zmm101342 小时前
基于微信小程序的乡村政务服务系统springboot+论文源码调试讲解
java·微信小程序·小程序·毕业设计·ssm
Oneforlove_twoforjob2 小时前
【Java基础面试题025】什么是Java的Integer缓存池?
java·开发语言·缓存
xmh-sxh-13142 小时前
常用的缓存技术都有哪些
java
AiFlutter3 小时前
Flutter-底部分享弹窗(showModalBottomSheet)
java·前端·flutter