前言:总结这两天学到的装饰者模式,并用java小小的实现一下。书中有写到:给爱用继承的人一个全新的设计眼界。(ps,本文最后有个小问题待解决)
定义:动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。
使用的设计原则:开放-关闭原则,类应该对扩展开放,对修改关闭。
代表:Java IO 流
类图:
优点:
缺点:
场景:现在需要炒一盘菜,可以给这盘菜加多种作料,这盘菜也可以有不同作料的组合。
实现:(如果只有一盘菜存在,不会再有第二盘菜的情况,也可以不创建抽象组件,直接创建具体组件,抽象的装饰类继承具体组件。)
1 /** 2 * 抽象组件 一盘菜 3 */ 4 abstract class Dish{ 5 protected String name; 6 7 public String getName(){ 8 return this.name; 9 } 10 }
1 /** 2 * 具体组件 3 */ 4 class MeatDish extends Dish{ 5 public MeatDish(){ 6 super.name = "meatDish"; 7 } 8 }
1 /** 2 * 抽象装饰类 作料 3 */ 4 abstract class Seasoning extends Dish{ 5 @Override 6 public abstract String getName(); 7 }
1 /** 2 * 具体装饰类 盐 3 */ 4 class Salt extends Seasoning{ 5 private Dish dish; 6 public Salt(Dish dish){ 7 this.dish = dish; 8 } 9 @Override 10 public String getName() { 11 return this.dish.getName() + " ,Salt"; 12 } 13 } 14 15 /** 16 * 具体装饰类,鸡精 17 */ 18 class ChickenPowder extends Seasoning{ 19 private Dish dish; 20 public ChickenPowder(Dish dish){ 21 this.dish = dish; 22 } 23 @Override 24 public String getName() { 25 return this.dish.getName() + " ,ChickenPowder"; 26 } 27 }
1 public static void main(String[] args){ 2 Dish dish = new MeatDish(); 3 System.out.println(dish.getName()); 4 5 dish = new Salt(dish); 6 dish = new ChickenPowder(dish); 7 System.out.println(dish.getName()); 8 }
问:不是说这个让爱用继承的人改变眼界吗?怎么类图还是使用的继承?
答: 这么做的重点在于,装饰者和被装饰者必须是一样的类型,也就是有共同的超类,这是相当关键的地方。在这里,是利用继承达到“类型匹配”,而不是利用继承获得“行为”。
问:那么行为从哪里来?
答:当我们将装饰者与组件组合时,就是在加入新的行为。所得到的新行为,并不是继承自超类,而是由组合对象得来的。如果这里依赖继承,那么类的行为只能只能在编译时静态决定。换句话说,行为如果不是来自超类,就是子类覆盖后的版本。反之,利用组合,可以把装饰者混合着用,而且是在运行时。这样,就可以在任何时候实现新的装饰者增加新的行为,如果依赖继承,每当需要新行为时,还得修改现有的代码。
问:为什么Componet要设计为一个抽象类,而不是一个接口?
答:通常装饰者模式是采用抽象类。(有大神知道的吗?还请不吝赐教)
参考书籍:《Head First 设计模式》《大话设计模式》
原文:https://www.cnblogs.com/yuxiaole/p/9220672.html