定义:装饰模式(Decorator),是在不必改变原类文件和使用继承的情况下,动态的扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。它主要是解决:“过度地使用了继承来扩展对象的功能”,由于继承为类型引入的静态特质,使得这种扩展方式缺乏灵活性;并且随着子类的增多(扩展功能的增多),各种子类的组合(扩展功能的组合)会导致更多子类的膨胀(多继承)。继承为类型引入的静态特质的意思是说以继承的方式使某一类型要获得功能是在编译时。所谓静态,是指在编译时;动态,是指在运行时。
特点:
(1)装饰对象和真实对象有相同的接口。这样客户端对象就可以和真实对象相同的方式和装饰对象交互。
(2)装饰对象包含一个真实对象的引用(reference)
(3)装饰对象接受所有来自客户端的请求。它把这些请求转发给真实的对象。
(4)装饰对象可以在转发这些请求以前或以后增加一些附加功能。这样就确保了在运行时,不用修改给定对象的结构就可以在外部增加附加的功能。在面向对象的设计中,通常是通过继承来实现对给定类的功能扩展。
类型:结构型模式
类图:
该模式中包含的角色及其职责
Component:定义一个对象接口,可以给这些对象动态的添加职责。
ConcreteComponent:定义一个对象可以给这个对象动态的添加职责。
Decorator:维护一个指向Component对象的指针,并定义一个与Component接口一致的接口,或者直接实现Component对象。
协作关系:Decorator把来自客户端的请求发送给所装饰的ConcreteComponent,在发送请求的前后执行一些附加的动作。
代码示例:
我们现在用的手机功能很多,我就用Decorator模式实现一下对某个手机的GSP和蓝牙功能扩展。
首先,我们需要一个手机的接口或者是抽象类,我这里就用抽象类来实现,代码如下:
package com.jin.model.decorator;
public abstract class AbstractCellPhone {
public abstract String callNumber();
public abstract String sendMessage();
}
AbstractCellPhone也就是结构图中的Component,然后,我再来实现Nokia和Moto的手机类,这类要继承AbstractCellPhone,也就是图中ConcreteComponent类要继承Component,实现代码如下:
package com.jin.model.decorator;
public class NokiaPhone extends AbstractCellPhone {
@Override
public String callNumber() {
return "NokiaPhone call sombody";
}
@Override
public String sendMessage() {
return "NokiaPhone send a message to somebody";
}
}
package com.jin.model.decorator;
public class MotoPhone extends AbstractCellPhone {
@Override
public String callNumber() {
return "MotoPhone call sombody";
}
@Override
public String sendMessage() {
return "MotoPhone send a message to somebody";
}
}
接下来我需要一个Decorator接口或者抽象类,实现代码如下:
package com.jin.model.decorator;
public abstract class Decorator extends AbstractCellPhone {
private AbstractCellPhone phone;
public Decorator(AbstractCellPhone phone) {
this.phone = phone;
}
@Override
public String callNumber() {
return phone.callNumber();
}
@Override
public String sendMessage() {
return phone.sendMessage();
}
}
正如结构图中,这个Decorator即继承了AbstractCellPhone,又包含了一个私有的AbstractCellPhone的对象。这样做的意义是:Decorator类又使用了另外一个Component类。我们可以使用一个或多个Decorator对象来“装饰”一个Component对象,且装饰后的对象仍然是一个Component对象。在下来,我要实现GSP和蓝牙的功能扩展,它们要继承自Decorator,代码如下:
package com.jin.model.decorator;
public class DecoratorBlueTooth extends Decorator {
public DecoratorBlueTooth(AbstractCellPhone phone) {
super(phone);
}
@Override
public String callNumber() {
return super.callNumber() + " with BlueTooth";
}
@Override
public String sendMessage() {
return super.sendMessage() + " with BlueTooth";
}
}
package com.jin.model.decorator;
public class DecoratorGPS extends Decorator {
public DecoratorGPS(AbstractCellPhone phone) {
super(phone);
}
@Override
public String callNumber() {
return super.callNumber() + " with GPS";
}
@Override
public String sendMessage() {
return super.sendMessage() + " with GPS";
}
}
最后,用客户端程序验证一下:
package com.jin.model.decorator;
public class Test {
/**
* @param args
*/
public static void main(String[] args) {
AbstractCellPhone phone = new NokiaPhone();
System.out.println(phone.callNumber());
System.out.println(phone.sendMessage());
AbstractCellPhone gps = new DecoratorGPS(phone);
System.out.println(gps.callNumber());
System.out.println(gps.sendMessage());
AbstractCellPhone bluetooth = new DecoratorBlueTooth(gps);
System.out.println(bluetooth.callNumber());
System.out.println(bluetooth.sendMessage());
}
}
执行结果:
NokiaPhone call sombody
NokiaPhone send a message to somebody
NokiaPhone call sombody with GPS
NokiaPhone send a message to somebodywith GPS
NokiaPhone call sombody with GPS withBlueTooth
NokiaPhone send a message to somebodywith GPS with BlueTooth
从执行的结果不难看出扩展功能已被添加。
装饰模式的几点要点:
1、通过采用组合、而非继承的手法,Decorator模式实现了在运行时动态的扩展对象功能的能力,而且可以根据需要扩展多个功能。避免了单独使用继承带来的“灵活性差”和“多子类衍生问题”。
2、Component类在Decorator模式中充当抽象接口的角色,不应该去实现具体的行为。而且Decorator类对于Component类应该透明——换言之Component类无需知道Decorator类,Decorator类是从外部来扩展Component类的功能。
3、Decorator类在接口上表现为is-a Component的继承关系,即Decorator类继承了Component类所具有的接口。但在实现上又表现为has-a Component的组合关系,即Decorator类又使用了另外一个Component类。我们可以使用一个或多个Decorator对象来“装饰”一个Component对象,且装饰后的对象仍然是一个Component对象。(在这里我想谈一下我的理解:当我们实例化一个Component对象后,要给这个对象扩展功能,这时我们把这个Component对象当作参数传给Decorator的子类的构造函数——也就是扩展方法的功能类。对于引用类型传参时,实际上只是传递对象的地址,这样,在功能扩展是,操作的应该是同一个对象)
4、Decorator模式并非解决“多子类衍生的多继承”问题,Decorator模式应用的要点在于解决“主体类在多个方向上的扩展功能”——是为“装饰”的含义。Decorator是在运行时对功能进行组合。
优缺点:
1. 比静态继承更灵活与对象的静态继承相比,Decorator模式提供了更加灵活的向对象添加职责的方式,可以使用添加和分离的方法,用装饰在运行时刻增加和删除职责。使用继承机制增加职责需要创建一个新的子类,如果需要为原来所有的子类都添加功能的话,每个子类都需要重写,增加系统的复杂度,此外可以为一个特定的Component类提供多个Decorator,这种混合匹配是适用继承很难做到的。
2. 避免在层次结构高层的类有太多的特征,Decorator模式提供了一种“即用即付”的方法来添加职责,他并不试图在一个复杂的可订制的类中支持所有可预见的特征,相反可以定义一个简单的类,并且用Decorator类给他逐渐的添加功能,可以从简单的部件组合出复杂的功能。
3. Decorator 与它的Component不一样 Decorator是一个透明的包装,如果我们从对象标识的观点出发,一个被装饰了的组件与这个组件是有差别的,因此使用装饰时不应该以来对象标识。
4. 产生许多小对象,采用Decorator模式进行系统设计往往会产生许多看上去类似的小对象,这些对象仅仅在他们相互连接的方式上有所不同。