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类的一个子类Sparrow。Sparrow类实现了Bird类fly方法,使得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()方法时,将该方法的返回值设置为100。Sparrow类的代码如下:
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