设计模式学习笔记(三:装饰模式)

1.1概述

    在许多设计中,可能需要改进类的某个对象的功能,而不是该类创建的全部对象,在这样的情况下,就可以使用装饰模式。

    例如,麻雀类的实例(麻雀)能够连续飞行100米,如果用麻雀类创建了5只麻雀,那么这5只麻雀都能连续飞行100米。假如想让其中一只麻雀能够连续飞行150米,那应当怎样做呢?一种比较好的办法就是给麻雀装上智能电子翅膀,智能电子翅膀可以使得麻雀不使用自己的翅膀就能飞行50米。

    装饰模式是动态地扩展一个对象的功能,而不需要改变原始类代码的一种成熟模式。在装饰模式中,“具体组件”类和“具体装饰”类是该模式中最重要的两个角色。“具体组件”类的实例称作“被装饰者”,“具体装饰”类的实例称为“装饰者”。“具体装饰”类需要包含有“具体组件”类的一个实例的引用,以便装饰“被装饰者”。例如,前面所述的麻雀类就是“具体组件”类,而一只麻雀就是“具体组件”类的一个实例,即是一个“被装饰者”,而安装了电子翅膀的麻雀就是“具体装饰”类的一个实例,即安装了电子翅膀的麻雀就是麻雀的“装饰者”。

 

1.2模式的结构

    装饰模式的结构中包括以下四种角色:

(1)抽象组件(Component):抽象组件是一个抽象类。抽象组件定义了“被装饰者”需要进行“装饰“的方法。

(2)具体组件(ConcreteComponent):具体组件是抽象组件的一个子类,具体组件的实例称为“被装饰者“。

(3)装饰(Decorator):装饰也是抽象组件的一个子类,但装饰还包含一个抽象组件声明的变量以保存“被装饰者“的引用。装饰可以是一个抽象类也可以是一个非抽象类,如果是非抽象类,该类的实例称为”装饰者“。

(4)具体装饰(ConcreteDecorator):具体装饰是装饰的一个非抽象子类,具体装饰的实例称为“装饰者“。

    装饰模式结构的类图如下所示:

 

 

 

1.3装饰模式的优点

(1)被装饰者和装饰者是松耦合关系。由于装饰仅仅依赖于抽象组件,因此具体装饰只知道它要装饰的对象是抽象组件某一个子类的实例,但不需要知道是哪一个具体子类。

(2)装饰模式满足“开-闭原则“。不必修改具体组件,就可以增加新的针对该具体组件的具体装饰。

(3)可以使用多个具体装饰来装饰具体组件组件的实例。

 

1.4适合使用装饰模式的情景

(1)程序希望动态地增强类的某个对象的功能,而又不影响到该类的其他对象。

(2)采用继承来增强对象功能不利于系统的扩展和维护。

 

 

1.5装饰模式的使用

  下面通过一个简单的实例,实现1.1概述中简单例子:假设系统中有一个Bird抽象类以及Bird类的一个子类SparrowSparrow类实现了Birdfly方法,使得Sparrow类创建的对象(麻雀)调用fly()方法能连续飞行100米。

  现在,用户需要两只鸟,无论是那种鸟都可以,但必须分别能连续飞行150米和200米。显然,现有的系统无法向用户提供这样的Bird对象,所以需要修改现有的系统。此处,使用装饰者模式,即可实现不必修改系统的代码,只需在系统中添加“装饰”,该系统将可以创建出用户需要的鸟。具体如下:

 首先看一下本实例构建框架具体类和1.2模式的结构中类图的对应关系,如下图3所示:

 

图3  具体编写类及接口与类图对应关系

(1)抽象组件

本问题中,抽象组件Bird规定了具体组件需要实现方法,Bird类的代码如下:

package com.liuzhen.three_decorator;

public abstract class Bird {
    public abstract int fly();
}

 

(2)具体组件

对于本问题,具体组件是Sparrow类,该类在实现fly()方法时,将该方法的返回值设置为100Sparrow类的代码如下:

package com.liuzhen.three_decorator;

public class Sparrow extends Bird{
    public final int DISTANCE = 100;
    public int fly(){
        return DISTANCE;
    }
}

 

(3)装饰

本问题中,装饰类是一个抽象类,该类包含有一个Bird声明的变量以保存“被装饰者”的引用。代码如下:

package com.liuzhen.three_decorator;

public abstract class Decorator extends Bird {
    protected Bird bird;
    public Decorator(){
        
    }
    public Decorator(Bird bird){
        this.bird = bird;
    }
}

 

(4)具体装饰

根据具体的问题,具体装饰经常委托“被装饰者”调用相应的方法。本问题中具体装饰类是SparrowDecorator类,该类的代码如下:

package com.liuzhen.three_decorator;

public class SparrowDecorator extends Decorator{
    public final int DISTANCE = 50;  //eleFly方法能飞50米
    SparrowDecorator(Bird bird){
        super(bird);                 //表示调用父类(Decorator)的构造函数
    }
    public int fly(){
        int distance = 0;
        distance = bird.fly() + eleFly();   //委托被装饰者bird调用fly(),然后再调用eleFly()
        return distance;
    }
    /*
     * eleFly()方法访问权限设置为private,其目的是使得客户程序只有调用fly方法才可以使用eleFly方法
     */
    private int eleFly(){             //装饰者新添加的方法
        return DISTANCE;
    }
}

 

(5)具体使用

    通过ThreeApllication类来具体实现上述相关类和接口,来实现适配器模式的运用,其代码如下:

package com.liuzhen.three_decorator;

public class ThreeApplication {
    public void needBird(Bird bird){
        int flyDistance = bird.fly();
        System.out.println("这只鸟能飞行"+flyDistance+"米");
    }
    public static void main(String[] args) {
        ThreeApplication client = new ThreeApplication();
        Bird sparrow = new Sparrow();          //sparrow只能飞行100米
        Bird sparrowDecorator1 = new SparrowDecorator(sparrow);   //sparrowDecorator1能飞行150米
        Bird sparrowDecorator2 = new SparrowDecorator(sparrowDecorator1); //sparrowDecorator2能飞行200米
        client.needBird(sparrowDecorator1);
        client.needBird(sparrowDecorator2);
    }
}

 

运行结果如下:

这只鸟能飞行150米
这只鸟能飞行200米

 

参考资料:

      1.Java设计模式/耿祥义,张跃平著.——北京:清华大学出版社,2009.5

posted @ 2016-10-19 21:15  舞动的心  阅读(1074)  评论(0编辑  收藏  举报