定义:动态的给一个对象添加一些额外的职责。就增加功能来说,Decorator模式相比生成子类更为灵活。
类型:对象结构型模式
别名:包装模式(Wrapper)
类图:
Decorator装饰模式是一种结构型模式,它主要是解决:“过度地使用了继承来扩展对象的功能”,由于继承为类型引入的静态特质,使得这种扩展方式缺乏灵活性;并且随着子类的增多(扩展功能的增多),各种子类的组合(扩展功能的组合)会导致更多子类的膨胀(多继承)。继承为类型引入的静态特质的意思是说以继承的方式使某一类型要获得功能是在编译时。所谓静态,是指在编译时;动态,是指在运行时。
装饰设计模式的结构
- Component:定义一个对象接口,可以给这些对象动态的添加职责。
- ConcreteComponent:定义一个对象可以给这个对象动态的添加职责。
- Decorator:维护一个指向Component对象的指针,并定义一个与Component接口一致的接口,或者直接实现Component对象。
协作关系:Decorator把来自客户端的请求发送给所装饰的ConcreteComponent,在发送请求的前后执行一些附加的动作。
实现代码
用Decorator模式实现一下对某个手机的GSP和蓝牙功能扩展
首先,定义一个手机的接口或者是抽象类,这里就用抽象类来实现,代码如下:
//抽象接口 --> Component
abstract class AbstractCellPhone{
public abstract String callNumber();
public abstract String sendMessage();
}
然后,再来实现Android和IPhone的手机类,这类要继承CellPhone,也就是图中ConcreteComponent类要继承Component,实现代码如下:
// Android厂商的手机 -->ConcreteComponent
class AndroidCellPhone extends AbstractCellPhone{
@Override
public String callNumber() {
return "callNumber from Android terminal";
}
@Override
public String sendMessage() {
return "sendMessage from Android terminal";
}
}
class IPhoneCellPhone extends AbstractCellPhone{
@Override
public String callNumber() {
return "callNumber from IPhone terminal";
}
@Override
public String sendMessage() {
return "sendMessage from IPhone terminal";
}
}
接下来需要定义一个接口或者抽象类 Decorator,实现代码如下:
//抽象接口 --> Decorator
abstract class Decorator extends AbstractCellPhone{
protected AbstractCellPhone mCellPhone;
public Decorator(AbstractCellPhone mCellPhone) {
this.mCellPhone = mCellPhone;
}
@Override
public String callNumber() {
return mCellPhone.callNumber();
}
@Override
public String sendMessage() {
return mCellPhone.sendMessage();
}
}
Decorator既继承了AbstractCellPhone,又包含了一个私有的AbstractCellPhone的对象。这样做的意义是:Decorator类又使用了另外一个Component类。我们可以使用一个或多个Decorator对象来“装饰”一个Component对象,且装饰后的对象仍然是一个Component对象。
紧接着,实现GSP和蓝牙的功能扩展,它们继承自Decorator,代码如下:
//具体装饰类 GPS功能扩展 --> ConcreteDecorator
class DecoratorGPS extends Decorator{
public DecoratorGPS(AbstractCellPhone mCellPhone) {
super(mCellPhone);
}
@Override
public String callNumber() {
return super.callNumber() +" GPS";
}
@Override
public String sendMessage() {
return super.sendMessage() +" GPS";
}
}
class DecoratorBlueTooth extends Decorator{
public DecoratorBlueTooth (AbstractCellPhone mCellPhone) {
super(mCellPhone);
}
@Override
public String callNumber() {
return super.callNumber() +" BlueTooth";
}
@Override
public String sendMessage() {
return super.sendMessage() +" BlueTooth";
}
}
最后,客户调用代码
//客户 Client
public class DecoratorClient {
/**
* @param args
*/
public static void main(String[] args) {
AbstractCellPhone mCellPhone = new AndroidCellPhone();
System.out.println(mCellPhone.callNumber() +"\n" +mCellPhone.sendMessage());
System.out.println("-------------------------------------------");
Decorator gps = new DecoratorGPS(mCellPhone);
System.out.println(gps.callNumber() +"\n" +gps.sendMessage());
System.out.println("-------------------------------------------");
Decorator bluetooth = new DecoratorBlueTooth(mCellPhone);
System.out.println(bluetooth.callNumber() +"\n" +bluetooth.sendMessage());
}
}
Decorator模式的优缺点
- 比静态继承更灵活 与对象的静态继承相比,Decorator模式提供了更加灵活的向对象添加职责的方式,可以使用添加和分离的方法,用装饰在运行时刻增加和删除职责。使用继承机制增加职责需要创建一个新的子类,如果需要为原来所有的子类都添加功能的话,每个子类都需要重写,增加系统的复杂度,此外可以为一个特定的Component类提供多个Decorator,这种混合匹配是适用继承很难做到的。
- 避免在层次结构高层的类有太多的特征,Decorator模式提供了一种“即用即付”的方法来添加职责,他并不试图在一个复杂的可订制的类中支持所有可预见的特征,相反可以定义一个简单的类,并且用Decorator类给他逐渐的添加功能,可以从简单的部件组合出复杂的功能。
- Decorator 与它的Component不一样 Decorator是一个透明的包装,如果我们从对象标识的观点出发,一个被装饰了的组件与这个组件是有差别的,因此使用装饰时不应该以来对象标识。
- 产生许多小对象,采用Decorator模式进行系统设计往往会产生许多看上去类似的小对象,这些对象仅仅在他们相互连接的方式上有所不同。
适用场景
- 在不影响其他对象的情况下,以动态透明的方式给单个对象添加职责
- 处理那些可以撤销的职责。
- 当不能采用生成子类的方法进行扩充时,一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类的树木呈爆炸性增长,另一种可能是因为定义被隐蔽或类定义不能用于生成子类。
最后,自己有一点点费解,Decorator完全可以不用继承自Component类 实现相同的功能,但是最终还是继承自 Component,不大明白