装饰者模式:动态的将额外的责任添加到对象上去,相对于继承,提供更加灵活的扩展方案。
装饰者模式,有4个抽象的类概念:
- 抽象构建类:被装饰对象的接口
- 具体的构建类:被装饰的对象
- 抽象装饰者:怎么进行装饰的接口
- 具体装饰者:具体装饰的对象
关系类图如下:
其中重点是:抽象装饰者接口继承了被装饰对象的接口,这点非常重要,它是能够进行动态装饰的关键,根据接口动态的去匹配具体构件类。
举例:
咖啡店原本提供有2种咖啡:CoffeeDarked深焙咖啡、CoffeeMixed混合咖啡,先需要在这2中咖啡中可以添加:Milk牛奶、Mocha摩卡。
思考:
按照上图分析结果,可以调出6中不同口味的咖啡。如果按照继承的逻辑,一种咖啡可能需要建立一个子类(或者实现类),此处就需要建6个子类。如果需要添加的不止牛奶和摩卡2种,那子类将非常庞大。
如果使用装饰者模式,就不需要建立6个子类,只需要建立2种具体装饰者类(Milk、Mocha),即可满足需求。
下面是代码实现:()
1)抽象构件类
1 /** 2 * 抽象构件类 3 * @author Administrator 4 * 5 */ 6 public interface Coffee { 7 /** 8 * 描述什么样的咖啡 9 * @return 10 */ 11 public abstract String getDescription(); 12 13 /** 14 * 计算咖啡的价格 15 * @return 16 */ 17 public abstract double count(); 18 }
2)具体构件类
1 /** 2 * 具体构件类:深焙咖啡 3 * @author Administrator 4 * 5 */ 6 public class CoffeeDarked implements Coffee { 7 8 @Override 9 public String getDescription() { 10 return "深焙咖啡"; 11 } 12 13 @Override 14 public double count() { 15 return 10; 16 } 17 }
1 /** 2 * 具体构建类:混合咖啡 3 * @author Administrator 4 * 5 */ 6 public class CoffeeMixed implements Coffee { 7 8 @Override 9 public String getDescription() { 10 return "混合咖啡"; 11 } 12 13 @Override 14 public double count() { 15 return 20; 16 } 17 }
3)抽象装饰者类
1 /** 2 * 咖啡装饰者接口 3 * @author Administrator 4 * 5 */ 6 public interface DecoratorCoffee extends Coffee { 7 8 public abstract String getDescription(); 9 10 }
4)具体装饰者类
1 /** 2 * 具体装饰者:加牛奶 3 * @author Administrator 4 * 5 */ 6 public class DecoratorMilk implements DecoratorCoffee { 7 8 private Coffee coffee; 9 10 public DecoratorMilk(Coffee coffee){ 11 this.coffee = coffee; 12 } 13 14 @Override 15 public double count() { 16 17 return coffee.count() + 5; 18 } 19 20 @Override 21 public String getDescription() { 22 return coffee.getDescription() + "加牛奶"; 23 } 24 }
1 /** 2 * 具体装饰者类:加摩卡 3 * @author Administrator 4 * 5 */ 6 public class DecoratorMocha implements DecoratorCoffee { 7 8 private Coffee coffee; 9 10 public DecoratorMocha(Coffee coffee){ 11 this.coffee = coffee; 12 } 13 14 @Override 15 public String getDescription() { 16 return coffee.getDescription() + "加摩卡"; 17 } 18 19 public double count() { 20 return coffee.count() + 2; 21 } 22 }
最后测试下:
1 public class DecoratorTest { 2 3 /** 4 * @param args 5 */ 6 public static void main(String[] args) { 7 8 //想要一杯混合咖啡 9 Coffee coffee1 = new CoffeeMixed(); 10 System.out.println(coffee1.getDescription() + " " + coffee1.count()); 11 12 // 想要一杯加牛奶的混合咖啡(对coffee1进行装饰,加上牛奶) 13 Coffee coffee2 = new DecoratorMilk(coffee1); 14 System.out.println(coffee2.getDescription() + " " + coffee2.count()); 15 16 // 想要一杯加摩卡加牛奶的深焙咖啡 17 Coffee coffee3 = new CoffeeDarked(); 18 coffee3 = new DecoratorMilk(coffee3); 19 coffee3 = new DecoratorMocha(coffee3);//进一步对加了牛奶的咖啡加上摩卡 20 System.out.println(coffee3.getDescription() + " " + coffee3.count()); 21 } 22 }
测试结果:
总结:
装饰者模式能实现动态的对对象进行扩展,主要有2点,一是,抽象装饰者类和具体的构建类有相同的接口,二是具体的装饰者类和抽象构建类之间有依赖(具体在UML中怎么称呼不太了解,之后在补习下),并且通过构造器依赖注入,在运行时,就根据具体的实现类注入了。这样就实现了对象动态扩展。
装饰者模式和代理模式的区别:
代理模式:给对象创建一个代理对象,由代理对象代替对象进行操作。
装饰者模式:给对象创建一个装饰类对象,对对象进行功能的扩展。