概念 :
装饰器模式(Decorator Pattern)是一种结构型设计模式,允许您在不改变现有对象结构的情况下,动态地将新功能附加到对象上。通过创建一个包装器类来扩展原始类的功能。这个包装器类具有与原始类相同的接口,并在内部持有一个指向原始对象的引用。通过将多个包装器链接在一起,可以递归地添加任意数量的功能。
特点 :
- 装饰器和被装饰对象实现相同接口,使得客户端无需关心具体类型。
- 可以动态地添加、删除或组合多个装饰器。
- 不需要修改已存在代码即可扩展功能。
优点 :
- 提供了灵活性和可扩展性,可以根据需要逐步增加或移除功能。
- 遵循开闭原则,不需要修改现有代码即可实现新功能。
- 具备了继承关系所缺乏的灵活性。
缺点 :
- 增加了系统中类的数量,在某些情况下可能会增加复杂度和理解难度。
- 如果使用不当,可能会导致过多嵌套或产生大量小粒度对象。
适用场景 :
- 当希望为一个对象动态地添加额外的功能时,可以使用装饰器模式。
- 当不适合使用继承来扩展对象功能时,可以考虑使用该模式。
实现方式 :
使用抽象类作为基础组件
实现原理:
- 定义一个抽象类,该抽象类定义了需要被包装和扩展功能的方法。
- 创建一个抽象装饰器类,它继承自该抽象类。这个抽象装饰器持有一个指向基础组件对象(即被包装对象)的引用。
- 在具体子类中,通过调用父级构造函数传入被包装对象,并重写相关方法,在其中添加额外功能并调用父级方法以保留原始行为。
实现代码:
java
// 抽象基础组件
abstract class Component {
public abstract void operation();
}
// 具体基础组件
class ConcreteComponent extends Component {
public void operation() {
System.out.println("执行具体操作");
}
}
// 抽象装饰器
abstract class Decorator extends Component {
protected Component component;
public Decorator(Component component) {
this.component = component;
}
public void operation() {
if (component != null) {
component.operation();
}
}
}
// 具体装饰器A
class ConcreteDecoratorA extends Decorator {
public ConcreteDecoratorA(Component component) {
super(component);
}
public void addedBehavior() {
System.out.println("新增附加行为 A");
}
public void operation(){
super.operation();
addedBehavior();
}
}
// 具体装饰器B
class ConcreteDecoratorB extends Decorator{
public ConcreteDecoratorB(Component comp){
super(comp);
}
public void addedBehavior(){
System.out.println("新增附加行为 B");
}
public void operation(){
super.operation();
addedBehavior();
}
}
// 使用示例
public class Main {
public static void main(String[] args) {
// 使用示例
Component component = new ConcreteComponent();
component = new ConcreteDecoratorA(component);
component.operation();
component = new ConcreteDecoratorB(component);
component.operation();
}
}
在上述示例中,我们定义了一个抽象基础组件类Component,它包含一个抽象方法operation()。然后创建了具体的基础组件类ConcreteComponent,它实现了这个抽象方法。
接下来,我们创建了一个抽象装饰器类Decorator,它也继承自基础组件类,并持有一个指向基础组件对象的引用。在装饰器类中,我们通过调用基础组件对象的operation()方法来实现具体功能。
然后,我们创建了两个具体装饰器类ConcreteDecoratorA和ConcreteDecoratorB,它们分别扩展了抽象装饰器类并添加了额外的功能。在这些具体装饰器中,我们首先调用父类的operation()方法来执行原始操作,然后再执行附加行为。
最后,在客户端代码中,我们创建一个具体基础组件对象,并使用多个具体装饰器对象进行包裹和扩展。通过调用最外层装饰器对象的operation()方法来触发整个装饰过程上所有操作的执行。
需要注意,在这种方式下,每次增加新类型或结构变化时都需要修改相关子类。这可能会导致代码的脆弱性。
使用接口作为基础组件
实现原理:
- 定义一个接口作为基础组件,该接口定义了需要被装饰的方法。
- 创建一个具体的基础组件类来实现该接口,并实现具体的业务逻辑。
- 创建一个抽象装饰器类,它也实现了相同的接口。这个装饰器持有一个指向基础组件对象的引用,并在其内部调用基础组件对象对应方法。
- 创建具体装饰器类来扩展功能。这些具体装饰器也是通过实现抽象装饰器并添加额外功能来实现。
实现代码:
java
// 基础组件
interface Component {
void operation();
}
// 具体基础组件
class ConcreteComponent implements Component {
public void operation() {
System.out.println("执行具体操作");
}
}
// 抽象装饰器
abstract class Decorator implements Component {
protected Component component;
public Decorator(Component component) {
this.component = component;
}
public void operation() {
if (component != null) {
component.operation();
}
}
}
// 具体装饰器A
class ConcreteDecoratorA implements Component {
private Component component;
public ConcreteDecoratorA(Component comp){
this.component = comp;
}
public void addedBehavior(){
System.out.println("新增附加行为 A");
}
public void operation(){
if(component != null){
component.operation();
}
addedBehavior();
}
}
// 具体装饰器B
class ConcreteDecoratorB implements Component {
private Component component;
public ConcreteDecoratorB(Component comp){
this.component = comp;
}
public void addedBehavior(){
System.out.println("新增附加行为 B");
}
public void operation(){
if(component != null){
component.operation();
}
addedBehavior();
}
}
public class Main {
public static void main(String[] args) {
// 使用示例
Component component = new ConcreteComponent();
component = new ConcreteDecoratorA(component);
component = new ConcreteDecoratorB(component);
component.operation();
}
}
在上述示例中,我们定义了一个基础组件接口Component,它包含一个方法operation()。
然后创建了具体的基础组件类ConcreteComponent,它实现了该接口并实现具体的业务逻辑。
接下来,我们创建了抽象装饰器类 Decorator ,它也实现了相同的接口。这个装饰器持有一个指向基础组件对象的引用,并在其内部调用基础组件对象对应方法。
然后,我们创建了两个具体装饰器类 ConcreteDecoratorA 和 ConcreteDecoratorB ,它们分别实现了该接口并扩展了功能。在这些具体装饰器中,我们首先调用基础组件对象的 operation() 方法来执行原始操作,然后再执行附加行为。
最后,在客户端代码中,我们创建一个具体基础组件对象,并使用多个具体装饰器对象进行包裹和扩展。通过调用最外层装饰器对象的 operation() 方法来触发整个装饰过程上所有操作的执行。
存在的问题:
- 需要在每个具体装饰器中重新声明所有方法,即使它们只是简单地委派给基础组件对象。
- 如果需要改变已有代码结构(例如新增一种新类型),则需要修改所有相关子类。
动态装饰器链
实现原理:
- 定义一个接口或抽象类作为基础组件,该接口或类定义了需要被装饰的方法。
- 创建具体的基础组件类来实现该接口或继承该抽象类,并实现具体的业务逻辑。
- 创建一个抽象装饰器类,它也实现了相同的接口或继承相同的抽象类。这个装饰器持有一个指向基础组件对象的引用,并在其内部调用基础组件对象对应方法。
- 在抽象装饰器中添加一个方法,用于动态地添加下一个具体装饰器到链中。
- 创建具体装饰器类来扩展功能。这些具体装饰器也是通过继承抽象装饰器并添加额外功能来实现。
实现代码:
java
// 基础组件
interface Component {
void operation();
}
// 具体基础组件
class ConcreteComponent implements Component {
public void operation() {
System.out.println("执行具体操作");
}
}
// 抽象装饰器
abstract class Decorator implements Component {
protected Component component;
protected Decorator nextDecorator;
public void setNextDecorator(Decorator decorator) {
this.nextDecorator = decorator;
}
public void operation() {
if (component != null) {
component.operation();
}
if (nextDecorator != null) {
nextDecorator.operation();
}
}
}
// 具体装饰器A
class ConcreteDecoratorA extends Decorator {
public ConcreteDecoratorA(Component comp){
this.component = comp;
}
public void addedBehavior(){
System.out.println("新增附加行为 A");
}
public void operation(){
if(component != null){
component.operation();
}
addedBehavior();
if(nextDecorator != null){
nextDecorator.operation();
}
}
}
// 具体装饰器B
class ConcreteDecoratorB extends Decorator {
public ConcreteDecoratorB(Component comp){
this.component = comp;
}
public void addedBehavior(){
System.out.println("新增附加行为 B");
}
public void operation(){
if(component != null){
component.operation();
}
addedBehavior();
if(nextDecorator!=null){
nextDecorator.operation();
}
}
}
public class Main {
public static void main(String[] args) {
// 使用示例
Component component = new ConcreteComponent();
ConcreteDecoratorA decoratorA = new ConcreteDecoratorA(component);
ConcreteDecoratorB decoratorB = new ConcreteDecoratorB(component);
decoratorA.setNextDecorator(decoratorB);
decoratorA.operation();
}
}
存在问题 :
使用动态装饰器链时可能会遇到以下问题:
- 链中每个节点都需要知道下一个节点,增加了耦合性和复杂性。
- 动态修改链可能会导致不可预测行为和难以调试。