设计模式之装饰者模式
概述
饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。
这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。
设计模式思想
装饰者模式的基本思想是用装饰者来包装组件使之成为一个同类型的新组件,所以在装饰者角色中,记录当前对象(一般是声明一个基类引用变量,构造器中传对象引用参数初始化此变量),利用多态技术,用基类对象引用最终被包裹后的对象(注意:每包裹一层就把之前的对象覆盖掉),就获得了组件和所有包裹过组件的行为。
目的:动态地给一个对象添加一些额外的职责。就增加功能来说,装饰器模式相比生成子类更为灵活。
从代码实现的角度来说,就是希望在不修改任何底层代码的情况下为对象赋予新的功能。当系统需要添加新功能的时候,通过新的代码来装饰原有类的核心职责或主要行为。这些新加入的代码相当于对原有核心代码的修饰,只在特定的应用场景下出现。
装饰者模式通过组合的方式来扩展对象的行为,而不依赖于继承,也就是说虽然类的框架中包含继承,但只是为了获取正确的类型,而不是继承一种行为。行为来自于装饰者和基础组件,或者与其他装饰者之间的组合关系。
装饰者模式特点:
装饰者和被装饰对象有相同的超类型。
你可以用一个或多个装饰者包装一个对象。
既然装饰者和被装饰对象有相同的超类型,所以在任何需要原始对象(被包装的)的场合,可以用装饰过的对象代替它。
装饰者可以在所委托被装饰者的行为之前与/或之后,加上自己的行为,以达到特定的目的。
- 对象可以在任何时候被装饰,所以可以在运行时动态地、不限量地用你喜欢的装饰者来装饰对象
涉及角色
(1)抽象构件角色:定义一个抽象接口,来规范准备附加功能的类。
(2)具体构件角色(即被装饰者):将要被附加功能的类,实现抽象构件角色接口。
(3)抽象装饰者角色:持有对具体构件角色的引用并定义与抽象构件角色一致的接口。
(4)具体装饰角色:实现抽象装饰者角色,负责为具体构件添加额外功能。
其中,被装饰者与抽象装饰者都继承与抽象构件角色,具体装饰角色继承与抽象装饰角色,之所以让装饰者和被装饰者继承于同一组件是想让装饰者和被装饰者具有统一的类型而非为了继承行为。
设计模式的用法
在装饰模式中的角色有:
- 抽象构件(Component)角色:给出一个抽象接口,以规范准备接收附加责任的对象。
- 具体构件(ConcreteComponent)角色:定义一个将要接收附加责任的类。
- 装饰(Decorator)角色:持有一个构件(Component)对象的实例,并定义一个与抽象构件接口一致的接口。
- 具体装饰(ConcreteDecorator)角色:负责给构件对象“贴上”附加的责任。
抽象构件角色
package com.designpattern.Decorator;
//抽象构件角色-齐天大圣
public interface TheGreatestSage {
void change ();
}
具体构件角色
package com.designpattern.Decorator;
//具体构件角色-孙悟空
public class SunWuKong implements TheGreatestSage{
@Override
public void change() {
// TODO Auto-generated method stub
System.out.println("我是齐天大圣-孙悟空");
}
}
装饰角色
package com.designpattern.Decorator;
//抽象装饰角色-七十二变
public class SeventyChanges implements TheGreatestSage{
private TheGreatestSage tSage;
public SeventyChanges(TheGreatestSage tSage) {
super();
this.tSage = tSage;
}
@Override
public void change() {
// TODO Auto-generated method stub
tSage.change();
}
}
具体装饰角色
package com.designpattern.Decorator;
//具体装饰角色-鱼儿变
public class Fish extends SeventyChanges{
public Fish(TheGreatestSage tSage) {
super(tSage);
// TODO Auto-generated constructor stub
}
@Override
public void change() {
// TODO Auto-generated method stub
System.out.println("七十二遍之鱼儿变");
}
}
package com.designpattern.Decorator;
//具体装饰角色-鸟儿变
public class Bird extends SeventyChanges {
public Bird(TheGreatestSage tSage) {
super(tSage);
// TODO Auto-generated constructor stub
}
@Override
public void change() {
// TODO Auto-generated method stub
System.out.println("七十二遍之鸟儿变");
}
}
测试类:
package com.designpattern.test;
import com.designpattern.Decorator.Bird;
import com.designpattern.Decorator.Fish;
import com.designpattern.Decorator.SunWuKong;
import com.designpattern.Decorator.TheGreatestSage;
/**
* 客户端测试类
* @author Administrator
*
*/
public class TestDecorator {
public static void main(String[] args) {
TheGreatestSage sage = new SunWuKong();
sage.change();
TheGreatestSage bird = new Bird(sage);
bird.change();
TheGreatestSage fish = new Fish(sage);
fish.change();
}
}
测试效果:
我是齐天大圣-孙悟空
七十二遍之鸟儿变
七十二遍之鱼儿变
优缺点及使用场景
优点:装饰类和被装饰类可以独立发展,不会相互耦合,装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。
缺点:多层装饰比较复杂。
使用场景:
- 需要扩展一个类的功能,或给一个类增加附加责任。
- 需要动态地给一个对象增加功能,这些功能可以再动态地撤销。
- 需要增加由一些基本功能的排列组合而产生的非常大量的功能,从而使继承关系变得不现实。