装饰器模式是常用设计模式之一,通过一个装饰类来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。
装饰器模式与代理模式非常像,区别是代理模式是原始功能上附加功能,而装饰器模式是增强原始功能。
代理模式:我(代理)不是你(原始类),我只是代表你的(部分或全部)能力,不会改变你的能力;
装饰器模式:我(装饰器)就是你(原始类),我是你的伪装,不仅有你的全部能力,还可以改变你的能力;
装饰类有两个特点:完全包装原始类和层层包装
- 要完全包装原始类,装饰类必须与原始类实现同一个接口,并实现相同的方法。装饰类通过组合原始类,在每个方法中调用原始类的方法。
//人类
interface HumanBeing {
//速度
public void velocity();
//反应
public void reaction();
//视野
public void vision();
}
//正常人
class Human implements HumanBeing {
//速度
public void velocity(){
System.out.println("速度:每小时走10公里");
}
//反应
public void reaction(){
System.out.println("反应:打不到飞行中的蚊子");
}
//视野
public void vision(){
System.out.println("视野:可看到10公里外事物");
}
}
//钢铁侠,普通人穿上的钢铁服
class IronMan implements HumanBeing {
HumanBeing human;
public IronMan(HumanBeing human) {
System.out.println("--变身钢铁侠------------");
this.human = human;
}
//速度
public void velocity(){
this.human.velocity();
System.out.println("速度:时速加上500公里,会飞了");
}
//反应
public void reaction(){
this.human.reaction();
System.out.println("反应:变快100倍,可以接住子弹");
}
//视野
public void vision(){
this.human.vision();
System.out.println("视野:视野增加到了30公里,同时看到多个目标");
}
}
//圣斗士,普通人穿上的圣衣
class holyWarriors implements HumanBeing {
HumanBeing human;
public holyWarriors(HumanBeing human) {
System.out.println("--变身圣斗士------------");
this.human = human;
}
//速度
public void velocity(){
this.human.velocity();
System.out.println("速度:时速加上200公里");
}
//反应
public void reaction(){
this.human.reaction();
System.out.println("反应:变快1000倍,可以削掉飞行中蚊子的翅膀");
}
//视野
public void vision(){
this.human.vision();
System.out.println("视野:视野添加了50公里");
}
}
public class Demo {
public static void main(String[] args) {
HumanBeing human= new Human();
//变身钢铁侠
physicalExamination(new IronMan(human));
//变身圣斗士
physicalExamination(new holyWarriors(human));
}
//体检
private static void physicalExamination(HumanBeing human){
human.velocity();
human.reaction();
human.vision();
}
}
//执行结果
--变身钢铁侠------------
速度:每小时走10公里
速度:时速加上500公里,会飞了
反应:打不到飞行中的蚊子
反应:变快100倍,可以接住子弹
视野:可看到10公里外事物
视野:视野增加到了30公里,同时看到多个目标
--变身圣斗士------------
速度:每小时走10公里
速度:时速加上200公里
反应:打不到飞行中的蚊子
反应:变快1000倍,可以削掉飞行中蚊子的翅膀
视野:可看到10公里外事物
视野:视野添加了50公里
通过IronMan、holyWarriors 两个类包装,对正常人的能力进行了增强。
- 装饰类还有一个特点,就是可以层层包装。
public class Demo {
public static void main(String[] args) {
HumanBeing human= new Human();
//变身钢铁侠之后又变身圣斗士,普通人有了钢铁侠和圣斗士的能力
physicalExamination(new holyWarriors(new IronMan(human)));
}
//体检
private static void physicalExamination(HumanBeing human){
human.velocity();
human.reaction();
human.vision();
}
}
//执行结果
--变身钢铁侠------------
--变身圣斗士------------
速度:每小时走10公里
速度:时速加上500公里,会飞了
速度:时速加上200公里
反应:打不到飞行中的蚊子
反应:变快100倍,可以接住子弹
反应:变快1000倍,可以削掉飞行中蚊子的翅膀
视野:可看到10公里外事物
视野:视野增加到了30公里,同时看到多个目标
视野:视野添加了50公里
类图:
装饰模式在实际使用中每一个装饰类都需要完全包装原始类,但并不是每个方法(能力)都会改变。如果每个装饰类都要去实现调用原始类的方法,显然这不符合KISS、DRY原则。所以会让装饰类继承一个抽象装饰类,由这个抽象装饰类调用原始类的方法。真正的装饰类扩展需要改变能力的方法。现在我们把人类增加一种能力“变形”,看怎么使用抽象装饰类。
//人类
public interface HumanBeing {
//速度
public void velocity();
//反应
public void reaction();
//视野
public void vision();
//变形
public void deformation();
}
//正常人
public class Human implements HumanBeing {
//速度
public void velocity(){
System.out.println("速度:每小时走10公里");
}
//反应
public void reaction(){
System.out.println("反应:打不到飞行中的蚊子");
}
//视野
public void vision(){
System.out.println("视野:可看到10公里外事物");
}
//变形
public void deformation(){
System.out.println("变形:不能变形");
}
}
//抽象装饰类:超人
public abstract class Superman implements HumanBeing {
HumanBeing human;
public Superman(HumanBeing human) {
this.human = human;
}
//速度
public void velocity(){
this.human.velocity();
}
//反应
public void reaction(){
this.human.reaction();
}
//视野
public void vision(){
this.human.vision();
}
//变形
public void deformation(){
this.human.deformation();
}
}
//钢铁侠,继承超人
public class IronMan extends Superman {
public IronMan(HumanBeing human) {
super(human);
System.out.println("--变身钢铁侠------------");
}
//速度
public void velocity(){
super.velocity();
System.out.println("速度:时速加上500公里,会飞了");
}
//反应
public void reaction(){
super.reaction();
System.out.println("反应:变快100倍,可以接住子弹");
}
//视野
public void vision(){
super.vision();
System.out.println("视野:视野增加到了30公里,同时看到多个目标");
}
//没有变形能力,所有不需要重写变形
}
//圣斗士,继承超人
public class holyWarriors extends Superman {
public holyWarriors(HumanBeing human) {
super(human);
System.out.println("--变身圣斗士------------");
}
//速度
public void velocity(){
super.velocity();
System.out.println("速度:时速加上200公里");
}
//反应
public void reaction(){
super.reaction();
System.out.println("反应:变快1000倍,可以削掉飞行中蚊子的翅膀");
}
//视野
public void vision(){
super.vision();
System.out.println("视野:视野添加了50公里");
}
//没有变形能力,所有不需要重写变形
}
//橡胶人,继承超人
public class RubberMan extends Superman {
public RubberMan(HumanBeing human) {
super(human);
System.out.println("--变身橡胶人------------");
}
//变形
public void deformation(){
super.deformation();
System.out.println("变形:可以变长");
}
}
类图:
装饰模式运用的是多用组合少用继承的设计思想。
装饰类的运用比较多,比较有代表性的是java.io类库: