装饰模式
装饰模式又名包装模式,装饰模式以对客户端透明的方式扩展对象的功能,是继承关系的一个替代方案。
在装饰模式中的角色有:
抽象构件角色:给出一个抽象接口,以规范准备接受附加责任的对象。
具体构件角色:定义一个将要接受附加责任的类;
装饰角色:持有一个构件对象的实例,并定义一个与抽象构件接口一致的接口;
具体装饰角色:负责给构件对象贴上附加的责任;
装饰模式具体就相当于你把一件件的东西都给挂上去,挂上去之后还会留下一个钩子,你要做的就是把一件东西给挂在另一件东西的身上就可以了。
可以拿悟空的七十二变来形容;
作为悟空,你可以变成鱼,变成鸟,变成了鱼,你就会游泳,变成了鸟,你就会飞翔了,但不管你变成了什么,你的本质都是齐天大圣;
下面是代码:
抽象构件角色:
public interface TheGreatestSage { public void move(); }
具体构件角色:
public class Monkey implements TheGreatestSage { @Override public void move() { //代码 System.out.println("Monkey Move"); } }
具体构件角色“大圣本尊”猴孙类;
public class Monkey implements TheGreatestSage { @Override public void move() { //代码 System.out.println("Monkey Move"); } }
抽象装饰角色 “七十二变”
public class Change implements TheGreatestSage { private TheGreatestSage sage; public Change(TheGreatestSage sage){ this.sage = sage; } @Override public void move() { // 代码 sage.move(); } }
具体装饰角色“鱼儿”
public class Fish extends Change { public Fish(TheGreatestSage sage) { super(sage); } @Override public void move() { // 代码 System.out.println("Fish Move"); } }
具体装饰角色“鸟儿”
public class Bird extends Change { public Bird(TheGreatestSage sage) { super(sage); } @Override public void move() { // 代码 System.out.println("Bird Move"); } }
客户端类
public class Client { public static void main(String[] args) { TheGreatestSage sage = new Monkey(); // 第一种写法 TheGreatestSage bird = new Bird(sage); TheGreatestSage fish = new Fish(bird); // 第二种写法 //TheGreatestSage fish = new Fish(new Bird(sage)); fish.move(); } }
上面的例子中, 系统把大圣从一只猴孙装饰成了一只鸟儿(把鸟儿的功能加到了猴孙的身上),然后又把鸟儿装饰成了一条鱼儿,(把鱼儿的功能加到猴孙+ 鸟儿身上,得到了猴孙+ 鸟儿 + 鱼儿);
装饰模式和适配模式都是“包装模式”,他们都是通过封装其他对象达到设计的目的,但是他们的形态有很大区别;
理想的装饰模式在对被装饰对象进行功能增强的同时,要求具体构件角色,装饰角色的接口与抽象构件角色的接口完全一致,而适配器模式则不然,一般而言,适配器模式并不要求对原对象的功能进行增强,但是会改变原对象的接口,以便和目标接口相符合。
装饰模式有透明和半透明两种,这两种的区别在于装饰角色的接口与抽象构件角色的接口是否完全一致。透明的装饰模式也就是理想的装饰模式,要求具体构件角色,装饰角色的接口与抽象构件角色的接口完全一致,相反,如果装饰角色的接口与抽象构件角色接口不一致,也就是说装饰角色的接口比抽象构件角色的接口宽,装饰角色实际上已经成了一个适配器角色,这种装饰模式是可以接受的,称为“半透明”的装饰模式;