• 设计模式(六)装饰模式


    装饰模式:

      装饰模式,又称包装模式(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。

  • 相关阅读:
    关于 Span 的一切:探索新的 .NET 明星:5. .NET 运行时的处理
    关于 Span 的一切:探索新的 .NET 明星: 3.什么是 Memory<T>,以及为什么你需要它?
    关于 Span 的一切:探索新的 .NET 明星: 4. Span<T> 和 Memory<T> 是如何与 .NET 库集成的?
    Configuring Kerberos with OpenLDAP backend
    gradle:secure protocol (like HTTPS) or allow insecure protocols
    Kerberos and LDAP
    EV录屏
    [转]在 WIN10 环境下,设置自己写的 程序 开机自动 启动的方法
    [转]go context之WithTimeout的使用
    [转]公司为什么要使用OKR,目的是什么?
  • 原文地址:https://www.cnblogs.com/jing-an-feng-shao/p/7634995.html
Copyright © 2020-2023  润新知