设计模式之装饰器模式

一、装饰器模式介绍

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

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

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

相关推荐
Sunlight_7774 分钟前
第五章 SQLite数据库:1、SQLite 基础语法及使用案例
java·linux·服务器·jvm·数据库·tcp/ip·sqlite
JhonKI14 分钟前
【从零实现高并发内存池】内存池整体框架设计 及 thread cache实现
java·redis·缓存
何似在人间57521 分钟前
SpringAI+DeepSeek大模型应用开发——4 对话机器人
java·机器人·大模型应用开发·spring ai
-曾牛1 小时前
【LangChain4j快速入门】5分钟用Java玩转GPT-4o-mini,Spring Boot整合实战!| 附源码
java·开发语言·人工智能·spring boot·ai·chatgpt
kfepiza1 小时前
HttpSessionListener 的用法笔记250417
java·笔记·servlet·tomcat
冬天vs不冷1 小时前
SpringBoot条件注解全解析:核心作用与使用场景详解
java·spring boot·python
百锦再1 小时前
Android Studio 实现自定义全局悬浮按钮
android·java·ide·app·android studio·安卓
百锦再2 小时前
Android Studio 项目文件夹结构详解
android·java·ide·ios·app·android studio·idea
阿达King哥2 小时前
Java虚拟机(JVM)平台无关?相关?
java·jvm
不是AI2 小时前
【Java编程】【计算机视觉】一种简单的图片加/解密算法
java·算法·计算机视觉