一、什么是装饰模式
装饰模式是一种设计模式,属于结构型模式之一。
在 Java 中,装饰模式通过动态地将责任附加到对象上,以扩展其功能,它提供了一种比继承更灵活的方式来扩展对象的功能。
在装饰模式中,有一个基础对象(被装饰对象)和一系列装饰器(装饰对象)。
装饰器和基础对象实现同一个接口,这样它们可以相互替换。
装饰器包含一个基础对象的引用,并将新的功能添加到基础对象上。
使用装饰模式,我们可以在运行时动态地扩展对象的功能,而不需要修改已有的代码 \color{red}{在运行时动态地扩展对象的功能,而不需要修改已有的代码}在运行时动态地扩展对象的功能,而不需要修改已有的代码,它将对象的行为和功能的扩展分离开来,使得代码更加灵活可扩展。
下面是一个简单的Java代码示例,请同学们复制到本地执行。
// 定义口 public interface Shape { void draw(); } // 实现接口的基础对象 public class Circle implements Shape { @Override public void draw() { System.out.println("画一个圆形"); } } // 实现接口的装饰器 public abstract class ShapeDecorator implements Shape { protected Shape decoratedShape; ShapeDecorator(Shape decoratedShape) { this.decoratedShape = decoratedShape; } @Override public void draw() { decoratedShape.draw(); } } // 具体的装饰器 public class RedShapeDecorator extends ShapeDecorator { public RedShapeDecorator(Shape decoratedShape) { super(decoratedShape); } @Override public void draw() { decoratedShape.draw(); setRedBorder(); } private void setRedBorder() { System.out.println("添加红色边框"); } } // 使用示例 public class Main { public static void main(String[] args) { Shape circle = new Circle(); // 使用装饰器功能扩展 Shape redCircle = new RedShapeDecorator(new Circle()); Shape redRectangle = new RedShapeDecorator(new Rectangle()); circle.draw(); // 输出:画一个圆形 redCircle.draw(); // 输出:画一个圆形,添加红色边框 redRectangle.draw(); // 输出:画一个长方,添加红色边框 } }
在这个例子中,Circle
是基础对象,ShapeDecorator
是装饰器,RedShapeDecorator
是具体的装饰器。
使用装饰器可以在运行时为基础对象添加新的功能,而不需要修改基础对象本的代码。
二、装饰模式实例
以下是一个简单的 Java 装饰模式的实例代码,请同学们复制到本地执行。
// 定义接口 interface Shape { void draw(); } // 实现接口的基础对象 class Circle implements Shape { @Override public void draw() { System.out.println("画一个圆形"); } } // 实现接口的装饰器 abstract class ShapeDecorator implements Shape { protected Shape decoratedShape; public ShapeDecorator(Shape decoratedShape) { this.decoratedShape = decoratedShape; } @Override public void draw() { decoratedShape.draw(); } } // 具体的装饰器 class RedShapeDecorator extends ShapeDecorator { public RedShapeDecorator(Shape decoratedShape) { super(decoratedShape); } @Override public void draw() { decoratedShape.draw(); setRedBorder(); } private void setRedBorder() { System.out.println("添加红色边框"); } } // 使用示例 public class Main { public static void main(String[] args) { Shape circle = new Circle(); // 使用装饰器功能扩展 Shape redCircle = new RedShapeDecorator(new Circle()); Shape redRectangle = new RedShapeDecorator(new Rectangle()); circle.draw(); // 输出:画一个圆形 redCircle.draw(); // 输出:画一个圆形,添加红色边框 redRectangle.draw(); // 输出:画一个长方形,添加红色边框 } }
在这个例子中,Circle
是基础对象,ShapeDecorator
是装饰器,RedShapeDecorator
是具体的装饰器。
使用装饰器可以在运行时为基础对象添加新的功能,而不需要修改基础对象本身的代码。
通过创建具体的装饰器并传入基础对象,可以动态地扩展对象的功能。
三、装饰模式的应用场景
装饰模式在以下 4 44 种情况下使用,请同学们有个基本的了解。
- 动态地给一个对象添加额外的功能,而不影响其他对象。
- 需要在不改变原有代码的情况下,对现有对象进行扩展。
- 需要通过组合而非继承来实现功能的扩展。
- 需要对一个对象的功能进行多次扩展,而使用继承会导致类的爆炸性增长。
当然,装饰模式的应用场景有以下 4 44 类,请同学们认真学习。
- IO 流操作:Java 中的 InputStream、OutputStream 等类就是典型的装饰模式的应用。通过装饰器模式,我们可以在运行时动态地为输入输出流添加新的功能,如缓冲、压缩等,而不需要修改原有的 IO 类。
- GUI 组件:在 GUI 应用程序中,我们经常需要为组件添加额外的装饰,如边框、滚动条等。装饰模式可以让我们在不改变组件类的情况下,动态地添加这些装饰。
- 日志记录:通过装饰模式,我们可以为日志记录器对象动态地添加新的功能,如加密、压缩等,而不需要修改原有的日志记录器类。
- 数据库操作:在数据库操作中,我们可以通过装饰模式为数据库连接对象添加额外的功能,如连接池管理、事务管理等。
总之,装饰模式在需要动态地为对象添加功能、扩展对象的行为且不改变原有代码的情况下,提供了一种灵活且可复用的方案。
四、装饰模式面试题
- 请解释什么是装饰模式,并举一个具体的例子。
- 装饰模式和继承有什么区别?
- 装饰模式的优点和缺点是什么?
- 装饰模式与适配器模式有何异同?
- 在什么情况下应该使用装饰模式?
- 装饰模式如何实现动态地给对象添加新的功能?
- 装饰模式中的组件接口和装饰器接口有何作用?
- 在装饰模式中,装饰器可以有多个吗?如果可以,如何管理多个装饰器之间的顺序?
- 装饰模式与代理模式有何区别?
- 装饰模式是否违反开闭原则?为什么?