设计模式——装饰模式

装饰模式

装饰模式能给一个对象动态添加一些额外的职责。就增加功能来说, Decorator 模式相比生成子类更为灵活。

装饰模式结构

在装饰模式中各个角色有:

  • 抽象构件(Component)角色: 给出一个抽象接口,以规范准备接收附加责任的对象。
  • 具体构件(Concrete Component)角色:定义一个要接收附加责任的类。
  • 装饰(Decorator)角色:持有一个构件(断肠和)对象的实例,并定义一个与抽象构件接口一致的接口。
  • 具体装饰(Decorator)角色:负责给构件对象 “贴上”附加的责任。

例子:

  1. 装饰模式动态地为对象附加额外的责任。添加到松树或冷杉树上的装饰品就是装饰模式的例子。灯光、花环、手杖糖果、玻璃装饰品等,都可以添加到树上,让它看起来更喜庆。这些装饰物不会改变圣诞树本身,不管使用什么特殊的装饰物,圣诞树都可以被认作圣诞树。作为附加功能的一个例子,灯的添加允许人们“点亮”圣诞树。
  2. 另一个例子:突击枪本身就是致命武器。但你可以应用某些“装饰”使它更精确、更安静、更具破坏性。

我们再从代码层面看一个例子:

使用装饰模式前


package DecoratorPattern.Before;


/**
 * 使用装饰模式前
 */

class A {
    public void doIt(){
        System.out.print('A');
    }
}

class AwithX extends A {
    @Override
    public void doIt() {
        super.doIt();
        doX();
    }

    private void doX(){
        System.out.print('X');
    }
}

class AwithY extends A {
    @Override
    public void doIt() {
        super.doIt();
        doY();
    }

    public void doY(){
        System.out.print('Y');
    }
}

class AwithZ extends A {
    @Override
    public void doIt() {
        super.doIt();
        doZ();
    }

    public void doZ() {
        System.out.print('Z');
    }
}

class AwithXY extends AwithX {

    private AwithY obj = new AwithY();

    @Override
    public void doIt() {
        super.doIt();
        obj.doY();
    }
}

class AwithXYZ extends AwithX {

    private AwithY obj1 = new AwithY();
    private AwithZ obj2 = new AwithZ();

    @Override
    public void doIt() {
        super.doIt();
        obj1.doY();
        obj2.doZ();
    }
}

public class DecoratorDemo{
    public static void main(String[] args) {
        A[] array = {new AwithX(), new AwithXY(), new AwithXYZ()};
        for (A a: array){
            a.doIt();
            System.out.print(' ');
        }
    }
}

使用装饰模式后


package DecoratorPattern.After;

/**
 * 使用装饰模式后
 */

interface I {
    void doIt();
}

class A implements I {

    @Override
    public void doIt() {
        System.out.print('A');
    }
}

abstract class D implements I {
    private I core;

    public D(I inner) {
        core = inner;
    }

    @Override
    public void doIt() {
        core.doIt();
    }
}

class X extends D {

    public X(I inner) {
        super(inner);
    }

    @Override
    public void doIt() {
        super.doIt();
        doX();
    }

    private void doX() {
        System.out.print('X');
    }
}

class Y extends D {

    public Y(I inner) {
        super(inner);
    }

    @Override
    public void doIt() {
        super.doIt();
        doY();
    }

    private void doY() {
        System.out.print('Y');
    }
}

class Z extends D {

    public Z(I inner) {
        super(inner);
    }

    @Override
    public void doIt() {
        super.doIt();
        doZ();
    }

    private void doZ() {
        System.out.print('Z');
    }
}

public class DecoratorDemo {
    public static void main(String[] args) {
      I[] array = {new X(new A()), new Y(new X(new A())), new Z(new Y(new X(new A())))};
      for (I anArray: array){
          anArray.doIt();
          System.out.print(' ');
      }
    }
}


优点:

  1. 装饰模式比静态继续更灵活。与对象的静态继承相比,装饰模式提供了更加灵活地向对象添加职责的方式。可以用添加和分享的方法,用装饰在运行时和删除职责。相比之下,继承机制要求为每个添加的职责创建一个新的子类。这会产生许多新的类,并且会增加系统复杂度。此外,为下个特定的 Component 类提供多个不同的 Decorator 类,这就使得你可以对一些职责进行混合和匹配。
  2. 避免在层次结构高层的类有太多的特征。装饰模式提供了一种”即用即付“的方法来添加职责。它并不试图在一个复杂的可定制的类中支持所有可预见的特征,相反,你可以定义一个简单的类,并且用 Decorator 类给它逐渐地添加功能。可以从简单的部件组合出复杂的功能。这样,应用程序不必为不需要的特征付出代价。

缺点:

  1. Decorator 与它的 Component 不一样。Decorator 是一个透明的包装。如果我们从对象标识的观点出发,一个被装饰了的组件与这个组件是有差别的,因此,使用装饰时不应该依赖对象标识。
  2. 有许多小对象。采用装饰模式进行系统设计往往会产生许多看上去类似的小对象,这些对象仅仅在它们相互连接的方式上有所不同,而不是它们的类或是它们的属性值有所不同。尽管对天那些了解这些系统的人来说,很容易对它们进行定制,但是很难学习这些系统,排错也很困难。

模式的简化

  1. 没有抽象的接口 Component 也是可以的,但 ConcreteComponent 就要扮演双重角色。

  1. 没有抽象的 Decorator 也是可以的,只是 ConcreteDecorator 需要扮演双重的角色。

参考:

https://sourcemaking.com/design_patterns/decorator

posted @ 2020-09-21 00:35  二十亿光年的孤独  阅读(156)  评论(0编辑  收藏  举报