真刀实枪之装饰模式
- 罪恶的成绩单--利用中庸之道来化解斥责
- 同是天涯沦落人:曾经的你有没有考完试让父母在试卷上签字的...
- 先将这件“为了我们好”的事用类图展示一下吧:
-
代码
-
SchoolReport
package com.peng.zsz; /** * @author kungfu~peng * @data 2017年11月22日 * @description */ public abstract class SchoolReport { // 成绩情况 public abstract void report(); // 家长签字 public abstract void sign(String name); }
-
FourthGradeSchoolReport
package com.peng.zsz; /** * @author kungfu~peng * @data 2017年11月22日 * @description */ public class FouthGradeSchoolReport extends SchoolReport { // 我的成绩单 @Override public void report() { // 成绩单的格式 System.out.println("尊敬的家长:"); System.out.println("您孩子的期末成绩为:【语文:78】【数学:67】【英语:69】"); System.out.println("家长签名:"); } // 家长签名 @Override public void sign(String name) { System.out.println("签名者:" + name); } }
- 接下来把这个成绩单给老爸看吧,类图增加Father
-
Father
package com.peng.zsz; /** * @author kungfu~peng * @data 2017年11月22日 * @description */ public class Father { public static void main(String[] args) { // 把成绩单拿过来 SchoolReport sr = new FouthGradeSchoolReport(); // 看成绩单 sr.report(); // 签名-----休想 } }
-
-
当然这不肯能在一个优秀设计者的童年出现,那么怎么办呢?
- 增加点技术工作:把成绩单封装一下
- 汇报最高成绩(心里战术:当最高成绩为80,你考了即使67,都会很容易接受)
- 汇报排名情况(不写总共有多少学生,只写写自己排多少名,钻个比较空子)
- 既然战术有了,先纸上谈个兵吧
-
代码
-
SugarFouthGradeSchoolReport
package com.peng.zsz; /** * @author kungfu~peng * @data 2017年11月22日 * @description */ public class SugarFouthGradeSchoolReport extends FouthGradeSchoolReport { // 定义美化方法--最高成绩 private void reportHighScore() { System.out.println("这次班里的最高分:【语文:88】【数学:90】【英语:87】"); } // 排名 private void sort() { System.out.println("这次排名:38名!"); } // 重写汇报方法 @Override public void report() { this.reportHighScore();// 润色--在、前奏 super.report();// 汇报真实情况 this.sort();// 汇报排名 } }
-
Father
package com.peng.zsz; /** * @author kungfu~peng * @data 2017年11月22日 * @description */ public class Father { public static void main(String[] args) { // 把成绩单拿过来 SchoolReport sr = new SugarFouthGradeSchoolReport(); // 看成绩单 sr.report(); // 签名 sr.sign("KungFu"); } }
- 执行效果
这次班里的最高分:【语文:88】【数学:90】【英语:87】 尊敬的家长: 您孩子的期末成绩为:【语文:78】【数学:67】【英语:69】 家长签名: 这次排名:38名! 签名者:KungFu
-
-
这次是躲过去了,纸是包不住火的,哪天父亲问班里有多少名同学时,这就尴尬了,难道继续扩展?类爆炸...
-
好办,定义一批专门负责装饰的类,类图如下
-
代码
-
Decorator
package com.peng.zsz; /** * @author kungfu~peng * @data 2017年11月22日 * @description */ public abstract class Decorator extends SchoolReport { // 成绩单 private SchoolReport sr; // 构造函数--将成绩单传进来 public Decorator(SchoolReport sr) { super(); this.sr = sr; } // 成绩单还是要被看到的 public void report() { this.sr.report(); } //看完要签名 public void sign(String name){ this.sr.sign(name); } }
-
HighScoreDecorator
package com.peng.zsz; /** * @author kungfu~peng * @data 2017年11月22日 * @description */ public class HighScoreDecorator extends Decorator { public HighScoreDecorator(SchoolReport sr) { super(sr); } // 定义美化方法--最高成绩 private void reportHighScore() { System.out.println("这次班里的最高分:【语文:88】【数学:90】【英语:87】"); } @Override public void report() { this.reportHighScore(); super.report(); } }
-
SortDecorator
package com.peng.zsz; /** * @author kungfu~peng * @data 2017年11月22日 * @description */ public class SortDecorator extends Decorator { public SortDecorator(SchoolReport sr) { super(sr); } // 排名 private void sort() { System.out.println("这次排名:38名!"); } @Override public void report() { this.sort(); super.report(); } }
-
Father
package com.peng.zsz; /** * @author kungfu~peng * @data 2017年11月22日 * @description */ public class Father { public static void main(String[] args) { // 把成绩单拿过来 SchoolReport sr; // 原装的成绩单 sr = new FouthGradeSchoolReport(); // 加了最高分的成绩单 sr = new HighScoreDecorator(sr); // 加了排名 sr = new SortDecorator(sr); // 汇报成绩 sr.report(); // 签名 sr.sign("KungFu"); } }
-
执行结果
这次排名:38名! 这次班里的最高分:【语文:88】【数学:90】【英语:87】 尊敬的家长: 您孩子的期末成绩为:【语文:78】【数学:67】【英语:69】 家长签名: 签名者:KungFu
-
-
-
- 增加点技术工作:把成绩单封装一下
装饰模式的定义
- Decorator Pattern
- Attach additional responsibilities to an object dynamically keeping the same interface.Decorator provide a flexible alternative to subclassing for extending functionality.(动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式相比生成子类更灵活)
-
通用类图
- 角色说明:
- Component抽象构件:是一个接口或抽象类,就是定义我们最核心的对象,也是最原始的对象
- ConcreteComponent具体构件:被装饰的对象
- Decorator装饰角色:重点--属性必须有被装饰者
- ConcreteDecorator具体装饰角色:具体装饰者
-
代码
-
Component
package zs2; /** * @author kungfu~peng * @data 2017年11月22日 * @description */ public abstract class Component { // 抽象方法 public abstract void operate(); }
-
ConcreteComponent
package zs2; /** * @author kungfu~peng * @data 2017年11月22日 * @description */ public class ConcreteComponent extends Component { @Override public void operate() { System.out.println("do Something!"); } }
-
Decorator
package zs2; /** * @author kungfu~peng * @data 2017年11月22日 * @description */ public abstract class Decorator extends Component { private Component component = null; // 构造函数--传递对象 public Decorator(Component component) { super(); this.component = component; } // 委托给被修饰者执行 @Override public void operate() { this.component.operate(); } }
-
ConcreteDecorator1
package zs2; /** * @author kungfu~peng * @data 2017年11月22日 * @description */ public class ConcreteDecorator1 extends Decorator { public ConcreteDecorator1(Component component) { super(component); } // 自定义修饰方法 private void method1() { System.out.println("修饰1"); } // 覆写方法 @Override public void operate() { this.method1(); super.operate(); } }
-
ConcreteDecorator2
package zs2; /** * @author kungfu~peng * @data 2017年11月22日 * @description */ public class ConcreteDecorator2 extends Decorator { public ConcreteDecorator2(Component component) { super(component); } // 自定义修饰方法 private void method2() { System.out.println("修饰2"); } // 覆写方法 @Override public void operate() { this.method2(); super.operate(); } }
-
Client
package zs2; /** * @author kungfu~peng * @data 2017年11月22日 * @description */ public class Client { public static void main(String[] args) { // 创建部件 Component component = new ConcreteComponent(); // 装饰1 component = new ConcreteDecorator1(component); // 在装饰1的基础上再装饰2 component = new ConcreteDecorator2(component); component.operate(); } }
-
执行结果
修饰2 修饰1 do Something!
-
- 角色说明:
装饰模式的应用
- 装饰模式的优点
- 装饰类和被装饰类可以独立发展,而不会互相耦合
- 装饰模式是继承关系的一个替换方案
- 装饰模式可以动态的扩展一个实现的功能
- 装饰模式的缺点
- 多层的装饰是比较复杂的---尽量减少装饰类的数量,以便降低系统的复杂度
- 装饰类的使用场景
- 需要扩展一个类的功能,或给一个类增加附加功能
- 需要动态的给一个对象增加功能,这些功能可以再动态的撤销
- 需要为一批的兄弟类进行改装或加装功能
最佳实践
- 装饰模式是对继承的有力补充,增加了其灵活性,解决了类膨胀的问题
- 装饰模式可以动态地增加功能
- 装饰模式的扩展性非常好,对于业务的变更,通过装饰模式来重封装一个类,而不是通过继承来完成
声明
- 摘自秦小波《设计模式之禅》第2版;
- 仅供学习,严禁商业用途;
- 代码手写,没有经编译器编译,有个别错误,自行根据上下文改正。