zoukankan      html  css  js  c++  java
  • 设计模式(六)装饰模式

    装饰模式:

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

  • 相关阅读:
    [ jquery 选择器 :hidden ] 此方法选取匹配所有不可见元素,或者type为hidden的元素
    剑指 Offer 03. 数组中重复的数字 哈希
    LeetCode 1736. 替换隐藏数字得到的最晚时间 贪心
    Leetcode 1552. 两球之间的磁力 二分
    Leetcode 88. 合并两个有序数组 双指针
    LeetCode 1744. 你能在你最喜欢的那天吃到你最喜欢的糖果吗?
    LeetCode 1743. 相邻元素对还原数组 哈希
    LeetCode 1745. 回文串分割 IV dp
    剑指 Offer 47. 礼物的最大价值 dp
    剑指 Offer 33. 二叉搜索树的后序遍历序列 树的遍历
  • 原文地址:https://www.cnblogs.com/jing-an-feng-shao/p/7634995.html
Copyright © 2011-2022 走看看