在阎宏博士的《JAVA与模式》一书中开头是这样描述装饰(Decorator)模式的:
装饰模式又名包装(Wrapper)模式。装饰模式以对客户端透明的方式扩展对象的功能,是继承关系的一个替代方案。
装饰模式的结构
装饰模式以对客户透明的方式动态地给一个对象附加上更多的责任。换言之,客户端并不会觉得对象在装饰前和装饰后有什么不同。装饰模式可以在不使用创造更多子类的情况下,将对象的功能加以扩展。
装饰模式的类图如下:
在装饰模式中的角色有:
● 抽象构件(Component)角色:给出一个抽象接口,以规范准备接收附加责任的对象。
● 具体构件(ConcreteComponent)角色:定义一个将要接收附加责任的类。
● 装饰(Decorator)角色:持有一个构件(Component)对象的实例,并定义一个与抽象构件接口一致的接口。
● 具体装饰(ConcreteDecorator)角色:负责给构件对象“贴上”附加的责任。
- //定义被装饰者
- public interface Human {
- public void wearClothes();
- public void walkToWhere();
- }
- //定义装饰者
- public abstract class Decorator implements Human {
- private Human human;
- public Decorator(Human human) {
- this.human = human;
- }
- public void wearClothes() {
- human.wearClothes();
- }
- public void walkToWhere() {
- human.walkToWhere();
- }
- }
- //下面定义三种装饰,这是第一个,第二个第三个功能依次细化,即装饰者的功能越来越多
- public class Decorator_zero extends Decorator {
- public Decorator_zero(Human human) {
- super(human);
- }
- public void goHome() {
- System.out.println("进房子。。");
- }
- public void findMap() {
- System.out.println("书房找找Map。。");
- }
- @Override
- public void wearClothes() {
- // TODO Auto-generated method stub
- super.wearClothes();
- goHome();
- }
- @Override
- public void walkToWhere() {
- // TODO Auto-generated method stub
- super.walkToWhere();
- findMap();
- }
- }
- public class Decorator_first extends Decorator {
- public Decorator_first(Human human) {
- super(human);
- }
- public void goClothespress() {
- System.out.println("去衣柜找找看。。");
- }
- public void findPlaceOnMap() {
- System.out.println("在Map上找找。。");
- }
- @Override
- public void wearClothes() {
- // TODO Auto-generated method stub
- super.wearClothes();
- goClothespress();
- }
- @Override
- public void walkToWhere() {
- // TODO Auto-generated method stub
- super.walkToWhere();
- findPlaceOnMap();
- }
- }
- public class Decorator_two extends Decorator {
- public Decorator_two(Human human) {
- super(human);
- }
- public void findClothes() {
- System.out.println("找到一件D&G。。");
- }
- public void findTheTarget() {
- System.out.println("在Map上找到神秘花园和城堡。。");
- }
- @Override
- public void wearClothes() {
- // TODO Auto-generated method stub
- super.wearClothes();
- findClothes();
- }
- @Override
- public void walkToWhere() {
- // TODO Auto-generated method stub
- super.walkToWhere();
- findTheTarget();
- }
- }
- //定义被装饰者,被装饰者初始状态有些自己的装饰
- public class Person implements Human {
- @Override
- public void wearClothes() {
- // TODO Auto-generated method stub
- System.out.println("穿什么呢。。");
- }
- @Override
- public void walkToWhere() {
- // TODO Auto-generated method stub
- System.out.println("去哪里呢。。");
- }
- }
- //测试类,看一下你就会发现,跟java的I/O操作有多么相似
- public class Test {
- public static void main(String[] args) {
- Human person = new Person();
- Decorator decorator = new Decorator_two(new Decorator_first(
- new Decorator_zero(person)));
- decorator.wearClothes();
- decorator.walkToWhere();
- }
- }
运行结果:
其实就是进房子找衣服,然后找地图这样一个过程,通过装饰者的三层装饰,把细节变得丰富。
关键点:
1、Decorator抽象类中,持有Human接口,方法全部委托给该接口调用,目的是交给该接口的实现类即子类进行调用。
2、Decorator抽象类的子类(具体装饰者),里面都有一个构造方法调用super(human),这一句就体现了抽象类依赖于子类实现即抽象依赖于实现的原则。因为构造里面参数都是Human接口,只要是该Human的实现类都可以传递进去,即表现出Decorator dt = new Decorator_second(new Decorator_first(new Decorator_zero(human)));这种结构的样子。所以当调用dt.wearClothes();dt.walkToWhere()的时候,又因为每个具体装饰者类中,都先调用super.wearClothes和super.walkToWhere()方法,而该super已经由构造传递并指向了具体的某一个装饰者类(这个可以根据需要调换顺序),那么调用的即为装饰类的方法,然后才调用自身的装饰方法,即表现出一种装饰、链式的类似于过滤的行为。
3、具体被装饰者类,可以定义初始的状态或者初始的自己的装饰,后面的装饰行为都在此基础上一步一步进行点缀、装饰。
4、装饰者模式的设计原则为:对扩展开放、对修改关闭,这句话体现在我如果想扩展被装饰者类的行为,无须修改装饰者抽象类,只需继承装饰者抽象类,实现额外的一些装饰或者叫行为即可对被装饰者进行包装。所以:扩展体现在继承、修改体现在子类中,而不是具体的抽象类,这充分体现了依赖倒置原则,这是自己理解的装饰者模式。