设计模式(六)装饰模式

装饰模式:

  装饰模式,又称包装模式(Wrapper),其作用在于,动态地为一个类添加职能。

  一般来说,为一个类添加额外的功能,第一个想到的应该是使用继承。

  在设计时,有这么一条准则:组合优于继承。  

  装饰模式,就是组合的一种应用,相比继承,它针对类的扩展更具有弹性。

如何理解更具有弹性:

  继承而言,子类与父类拥有很高的一致性,这种紧耦合使得继承在面对扩展或者变更时,对现有代码的复用性很弱。

  装饰模式中,将需要扩展功能的类,嵌入到另一个,专门负责扩展功能的类中,从而达到解耦的目的。

  以上两者,可以独自的扩展,互不影响。

使用场景:

  一般而言,遇到一下三种情况时,考虑使用装饰模式:

  1. 需要扩展一个类的功能,或给一个类增加附加责任。
  2. 需要动态的给一个对象增加功能,这些功能可以再动态地撤销。
  3. 需要增加一些基本功能的排列组合而产生的非常大量的功能。

角色分析:

  先用一张别人博客中看到的 UML 类图(链接):

  装饰模式,主要由以下4部分组成:

Component:抽象构件,抽象类或接口,定义被装饰类的行为。

ConcreteComponent:具体构件,被装饰类。

Decorator:装饰角色,持有被装饰类对象的实例,与其拥有相同的继承/实现关系。

ConcreteDecorator:具体装饰角色,为被装饰类,添加额外的职能。

  在一些简单的应用场景中,以上4部分可以依据实际情况,合并一部分。

代码:

1 public interface Component {
2 
3     void methodA();
4 
5     void methodB();
6 
7 }
Component
 1 public class ConcreteComponent implements Component {
 2 
 3     @Override
 4     public void methodA() {
 5         System.out.println(this.getClass().getName() + ": MethodA");
 6     }
 7 
 8     @Override
 9     public void methodB() {
10         System.out.println(this.getClass().getName() + ": MethodB");
11     }
12 
13 }
ConcreteComponent
 1 @AllArgsConstructor
 2 public abstract class Decorator implements Component {
 3 
 4     private Component component;
 5 
 6     @Override
 7     public void methodA() {
 8         component.methodA();
 9     }
10 
11     @Override
12     public void methodB() {
13         component.methodB();
14     }
15 
16 }
Decorator
 1 public class ConcreteDecoratorA extends Decorator {
 2 
 3     public ConcreteDecoratorA(Component component) {
 4         super(component);
 5     }
 6 
 7     public void methodC() {
 8         System.out.println(this.getClass().getName() + ": MethodC");
 9     }
10 
11 }
ConcreteDecoratorA
 1 @Data
 2 @EqualsAndHashCode(callSuper = false)
 3 public class ConcreteDecoratorB extends Decorator {
 4 
 5     private Object specificatedField;
 6 
 7     public ConcreteDecoratorB(Component component) {
 8         super(component);
 9     }
10 
11     @Override
12     public synchronized void methodA() {
13         System.out.println("Some operation before");
14         super.methodA();
15     }
16 
17 }
ConcreteDecoratorB

  以上代码中:

  装饰类A(ConcreteDecoratorA),为对象添加了额外的功能(methodC)。

  装饰类B(ConcreteDecoratorB),增加了额外的属性(specificatedField),并且为原有的操作,增加了一些修饰(methodA)。

典型应用:

  在 JDK 源码中,对装饰模式的最典型应用,莫过于 IO 流的设计了。

  所有 IO 流相关的类,都是从输入(InputStream)/输出(OutputStream)流这两个类扩展而成的。

  以下是我截取了 InputStream 结构中的部分设计,绘制的 UML:

  不难发现,IO 流中的结构,可以与装饰模式中的角色一一对应:

Component -> InputStream。

ConcreteComponent -> ByteArrayInputStream, FileInputStream。

Decorator -> FilterInputStream。

ConcreteDecorator -> DataInputStream, BufferInputStream, PushbackInputStream。

原文地址:https://www.cnblogs.com/jing-an-feng-shao/p/7634995.html