博主介绍: ✌博主从事应用安全和大数据领域,有8年研发经验,5年面试官经验,Java技术专家✌
Java知识图谱点击链接:体系化学习Java(Java面试专题)
💕💕 感兴趣的同学可以收藏关注下 ,不然下次找不到哟💕💕
1、什么是装饰者模式
装饰者模式(Decorator Pattern)是一种结构型设计模式,它允许你向一个现有的对象添加新的功能,同时又不改变其结构。装饰者模式基于组合而非继承的原则,它动态地将责任附加到对象上。
装饰者模式涉及到四个角色:抽象组件、具体组件、抽象装饰者和具体装饰者。其中,抽象组件定义了组件的基本功能,具体组件实现了组件的基本功能,抽象装饰者定义了装饰者的基本功能,具体装饰者实现了装饰者的基本功能,并且可以添加额外的功能。
装饰者模式的优点是可以动态地添加或删除对象的功能,而不需要修改现有的代码。它还可以避免使用子类来扩展对象的功能,从而减少类的数量。缺点是装饰者模式会增加许多小对象,从而增加系统的复杂性。
2、装饰者模式的优缺点
装饰者模式的优点包括:
可以动态地添加或删除对象的功能,而不需要修改现有的代码。
可以避免使用子类来扩展对象的功能,从而减少类的数量。
可以将多个装饰者组合起来,实现更复杂的功能。
装饰者模式的缺点包括:
装饰者模式会增加许多小对象,从而增加系统的复杂性。
装饰者模式可能会导致设计变得过于抽象,从而难以理解和维护。
装饰者模式可能会影响程序的性能,因为每个装饰者都会增加额外的处理时间。
3、装饰者模式的应用场景
装饰者模式通常适用于以下场景:
在不影响现有对象结构的情况下,动态地添加额外的功能或行为。
需要扩展一个类的功能,但是使用继承会导致类的数量增加,且不利于维护。
需要在不修改代码的情况下,对对象的某些功能进行组合或移除。
需要对一个对象的功能进行多次扩展或组合,而不是一次性地进行全部扩展或组合。
需要在运行时动态地添加或删除对象的功能。
需要在不破坏封装性的前提下,对对象的功能进行扩展或修改。
需要对对象的功能进行动态排序或过滤。
需要对对象的功能进行动态配置或组合。
总之,装饰者模式适用于需要动态地添加或删除对象的功能,同时又不希望对现有对象结构进行修改的场景。
4、装饰者模式的结构
装饰者模式的结构包括以下组件:
抽象组件(Component):定义了组件的接口,可以是抽象类或接口。
具体组件(Concrete Component):实现了抽象组件的接口,提供了基本的功能。
抽象装饰者(Decorator):定义了装饰者的接口,包含一个指向抽象组件的引用。
具体装饰者(Concrete Decorator):实现了抽象装饰者的接口,对抽象组件添加了新的功能。
装饰者模式使用组合而非继承的方式,动态地将责任附加到对象上,从而实现了动态地扩展对象的功能。它可以在不修改现有代码的情况下,动态地添加或删除对象的功能,同时避免了使用子类来扩展对象的功能,从而减少了类的数量。
5、装饰者模式的代码案例
假设有一个饮料类(Beverage),它有一个描述(description)和一个计算价格(cost)的方法。现在需要给这个饮料类添加一些调料(Condiment),比如牛奶、摩卡等,这些调料也有自己的描述和价格。使用装饰者模式,可以动态地添加或删除调料,而不需要修改饮料类的代码。
首先,我们定义一个饮料类Beverage,它是一个抽象类,包含描述和计算价格两个方法:
package com.pany.camp.design.principle.decorators;
/**
*
* @description: 抽象类
* @copyright: @Copyright (c) 2022
* @company: Aiocloud
* @author: pany
* @version: 1.0.0
* @createTime: 2023-06-27 20:37
*/
public abstract class Beverage {
String description = "Unknown Beverage";
public String getDescription() {
return description;
}
public abstract double cost();
}
然后,我们定义一个具体的饮料类Espresso,它继承自Beverage类,实现了cost方法和description属性:
package com.pany.camp.design.principle.decorators;
/**
*
* @description: 抽象实现
* @copyright: @Copyright (c) 2022
* @company: Aiocloud
* @author: pany
* @version: 1.0.0
* @createTime: 2023-06-27 20:38
*/
public class Espresso extends Beverage {
public Espresso() {
description = "Espresso";
}
public double cost() {
return 1.99;
}
}
接下来,我们定义一个抽象的调料类CondimentDecorator,它也是一个抽象类,继承自Beverage类,包含一个抽象的getDescription方法:
package com.pany.camp.design.principle.decorators;
/**
*
* @description: 抽象的调料类
* @copyright: @Copyright (c) 2022
* @company: Aiocloud
* @author: pany
* @version: 1.0.0
* @createTime: 2023-06-27 20:38
*/
public abstract class CondimentDecorator extends Beverage {
public abstract String getDescription();
}
然后,我们定义一个具体的调料类Milk,它继承自CondimentDecorator类,包含一个Beverage类型的成员变量和一个构造方法,用于接收一个饮料对象,然后将其保存到成员变量中。getDescription方法会调用Beverage对象的getDescription方法,并在其后面添加", Milk"。cost方法会调用Beverage对象的cost方法,并加上0.10的价格:
package com.pany.camp.design.principle.decorators;
/**
*
* @description: 具体的调料类Milk
* @copyright: @Copyright (c) 2022
* @company: Aiocloud
* @author: pany
* @version: 1.0.0
* @createTime: 2023-06-27 20:39
*/
public class Milk extends CondimentDecorator {
Beverage beverage;
public Milk(Beverage beverage) {
this.beverage = beverage;
}
public String getDescription() {
return beverage.getDescription() + ", Milk";
}
public double cost() {
return beverage.cost() + 0.10;
}
}
类似地,我们定义另一个具体的调料类Mocha,它也继承自CondimentDecorator类,包含一个Beverage类型的成员变量和一个构造方法,用于接收一个饮料对象,然后将其保存到成员变量中。getDescription方法会调用Beverage对象的getDescription方法,并在其后面添加", Mocha"。cost方法会调用Beverage对象的cost方法,并加上0.20的价格:
package com.pany.camp.design.principle.decorators;
/**
*
* @description: 具体的调料类Mocha
* @copyright: @Copyright (c) 2022
* @company: Aiocloud
* @author: pany
* @version: 1.0.0
* @createTime: 2023-06-27 20:40
*/
public class Mocha extends CondimentDecorator {
Beverage beverage;
public Mocha(Beverage beverage) {
this.beverage = beverage;
}
public String getDescription() {
return beverage.getDescription() + ", Mocha";
}
public double cost() {
return beverage.cost() + 0.20;
}
}
最后,我们可以使用如下的测试代码来测试我们的装饰者模式:
package com.pany.camp.design.principle.decorators;
/**
* @description: 客户端
* @copyright: @Copyright (c) 2022
* @company: Aiocloud
* @author: pany
* @version: 1.0.0
* @createTime: 2023-06-27 20:40
*/
public class Client {
public static void main(String[] args) {
Beverage beverage = new Espresso();
System.out.println(beverage.getDescription() + " $" + beverage.cost());
beverage = new Milk(beverage);
System.out.println(beverage.getDescription() + " $" + beverage.cost());
beverage = new Mocha(beverage);
System.out.println(beverage.getDescription() + " $" + beverage.cost());
}
}
输出结果为:
Espresso $1.99
Espresso, Milk $2.09
Espresso, Milk, Mocha $2.29
Process finished with exit code 0
可以看到,通过装饰者模式,我们动态地给饮料类添加了调料,而不需要修改饮料类的代码。
💕💕 本文由激流原创,首发于CSDN博客,博客主页 https://blog.csdn.net/qq_37967783?spm=1010.2135.3001.5421
💕💕喜欢的话记得点赞收藏啊