你好,这里是codetrend专栏“跟着GPT学设计模式”。
说明
装饰者模式是一种结构型设计模式,它允许你在不修改已有对象的情况下,动态地向对象添加额外的功能。装饰者模式通过包装原始对象来扩展其功能,并提供了一种灵活的方式来组合多个装饰器。装饰器模式主要解决继承关系过于复杂的问题,通过组合来替代继承。它主要的作用是给原始类添加增强功能。
使用mermaid绘制的桥接模式类图如下:
- Component(抽象组件):定义了被装饰者和装饰者的共同接口,包含 operation() 方法。
- ConcreteComponent(具体组件):实现了抽象组件的接口,并提供了具体的操作。
- Decorator(抽象装饰者):继承了抽象组件,持有一个抽象组件类型的引用,并在其构造函数中接收被包装的具体组件实例。它同时也实现了抽象组件的接口,以便与具体组件保持一致。
- ConcreteDecorator(具体装饰者):继承了抽象装饰者,并实现了具体的装饰逻辑。它可以通过调用父类的方法来扩展原始行为,并在需要时添加额外的功能。
该示意图中展示了一个简单的装饰者模式示例,其中 ConcreteComponent 是被装饰的对象,而 Decorator 和 ConcreteDecorator 是用于装饰该对象的装饰者。
装饰者模式的工作流程如下:
- 客户端创建一个具体组件的实例,并根据需要使用抽象装饰者对其进行包装。
- 抽象装饰者持有一个抽象组件的引用,并在其构造函数中接收被包装的具体组件实例。
- 抽象装饰者通过调用持有的抽象组件引用来实现共同接口的方法,可以在方法的前后添加额外的功能。
- 具体装饰者继承抽象装饰者,并实现自己的装饰逻辑。具体装饰者可以通过调用父类的方法来扩展原始行为。
使用装饰者模式的好处是,它允许你动态地向对象添加功能,而无需修改已有代码。它遵循开闭原则,使得系统更灵活且易于扩展。此外,装饰者模式通过组合多个装饰器,可以实现各种不同的组合效果。
应用场景
项目中使用装饰者模式的例子是 Java IO 库中的输入输出流(InputStream 和 OutputStream)。
在 Java IO 中,InputStream 和 OutputStream 是抽象组件,它们定义了读取和写入数据的基本接口。而具体组件则是实现了这些接口的类,例如 FileInputStream 和 FileOutputStream。
使用装饰者模式时,我们可以创建一个抽象装饰者类 FilterInputStream(继承自 InputStream),它持有一个被包装的 InputStream 对象,并通过调用父类的方法来扩展原始行为。
Java IO 中有许多具体装饰者类,例如 BufferedInputStream(用于提供缓冲读取功能)和 DataInputStream(用于读取不同类型的数据)。这些具体装饰者类继承自 FilterInputStream,通过调用父类的方法来扩展原始的读取行为,并在需要时添加额外的功能。
下面是一个简化的示例代码:
// 抽象组件
public abstract class InputStream {
public abstract int read();
}
// 具体组件
public class FileInputStream extends InputStream {
public int read() {
// 实现读取文件的逻辑
}
}
// 抽象装饰者
public abstract class FilterInputStream extends InputStream {
protected InputStream inputStream;
public FilterInputStream(InputStream inputStream) {
this.inputStream = inputStream;
}
public int read() {
// 调用被装饰的 InputStream 对象的 read() 方法
return inputStream.read();
}
}
// 具体装饰者
public class BufferedInputStream extends FilterInputStream {
public BufferedInputStream(InputStream inputStream) {
super(inputStream);
}
public int read() {
// 在调用父类的 read() 方法前后添加额外的缓冲读取功能
// ...
return super.read();
}
}
// 举例
public class FileToTextConverter {
public static void main(String[] args) {
String filePath = "path/to/your/file.txt"; // 替换为实际的文件路径
try (FileInputStream fis = new FileInputStream(filePath);
BufferedInputStream bis = new BufferedInputStream(fis)) {
StringBuilder sb = new StringBuilder(); // 使用 StringBuilder 储存文本内容
byte[] buffer = new byte[8192]; // 使用缓冲区进行读取,这里设置为 8KB
int bytesRead;
while ((bytesRead = bis.read(buffer)) != -1) {
sb.append(new String(buffer, 0, bytesRead));
}
String text = sb.toString(); // 将 StringBuilder 转换为字符串
System.out.println(text); // 打印文件内容
} catch (IOException e) {
e.printStackTrace();
}
}
}
编程示例
步骤1:创建抽象组件(Component)
public interface Beverage {
String getDescription();
double getCost();
}
步骤2:创建具体组件(ConcreteComponent)
public class Espresso implements Beverage {
public String getDescription() {
return "Espresso";
}
public double getCost() {
return 1.99;
}
}
步骤3:创建抽象装饰者(Decorator)
public abstract class CondimentDecorator implements Beverage {
protected Beverage beverage;
public CondimentDecorator(Beverage beverage) {
this.beverage = beverage;
}
public abstract String getDescription();
public abstract double getCost();
}
步骤4:创建具体装饰者(ConcreteDecorator)
public class Milk extends CondimentDecorator {
public Milk(Beverage beverage) {
super(beverage);
}
public String getDescription() {
return beverage.getDescription() + ", Milk";
}
public double getCost() {
return beverage.getCost() + 0.5;
}
}
public class Mocha extends CondimentDecorator {
public Mocha(Beverage beverage) {
super(beverage);
}
public String getDescription() {
return beverage.getDescription() + ", Mocha";
}
public double getCost() {
return beverage.getCost() + 0.3;
}
}
步骤5:使用装饰者模式
public class App {
public static void main(String[] args) {
// 创建一个具体组件对象
Beverage espresso = new Espresso();
// 使用装饰者对具体组件进行包装
Beverage milkEspresso = new Milk(espresso);
Beverage mochaMilkEspresso = new Mocha(milkEspresso);
// 进行操作,输出描述和总价格
System.out.println(mochaMilkEspresso.getDescription());
System.out.println("Cost: $" + mochaMilkEspresso.getCost());
}
}
输出结果:
Espresso, Milk, Mocha
Cost: $2.79
在上述示例中,我们创建了一个咖啡饮料的例子。Beverage 是抽象组件,Espresso 是具体组件;CondimentDecorator 是抽象装饰者,Milk 和 Mocha 是具体装饰者。通过装饰者模式,我们可以给具体组件添加额外的装饰来扩展其功能。
在 Main 类中,我们创建了一个 Espresso 的实例,并使用 Milk 和 Mocha 装饰它,最后输出了装饰后的描述和总价格。
以上内容基于GPT创建和整理。
关于作者
来自一线全栈程序员nine的探索与实践,持续迭代中。
欢迎关注公众号“雨林寻北”或添加个人卫星codetrend(备注技术)。