设计模式之装饰模式
装饰模式简单来讲就是在不改变一个对象原有的逻辑的前提下,添加其他的逻辑。
举例说明:到了年尾了,公司要求每个都对自己的工作做一份报告,总结下一年的工作,首先是A同事总结:“我是XXXX,今年主要是完成指定的需求,巴拉巴拉…”,都是将自己做的一板一眼的讲出来,不带任何感情。领导听得都要快睡着了,虽然做了那么多,领导可能也觉得只是一个按部就班做事儿的人,没有什么出彩的地方,可能直接导致年终奖缩水(呜呜呜…)。
轮到B同事总结(实际上跟A同事做的事情一样多,但是说出来就不一样):“尊敬的各位领导/同事,我是XXXX,今年主要是完成指定的需求,通过完成不同的需求,让自己对业务更加熟悉和理解,在完成需求的同时,也对以前的一些逻辑做重构,降低后期的维护成本,balaba…”,在讲解了自己工作的同时,不忘总结,突出自己的价值,以及在工作中学到的一些东西等等,目的就是为了让领导觉得自己不仅能做事,还会做事,交代的是一,实际完成的是三,这样领导就会觉得这个小伙子很有前途,搞不好优秀员工就到手了。
以上是描述的一个现实中存在的一个情况,下面用代码描述出来:
/**
* 年终总结
*/
public class EndOfYearConclusion {
//A同事的年终总结
static class AConclusion{
//自我介绍
public void introduce(){
System.out.println("我是A....");
}
//报告内容(毫无技术含量)
public void report(){
System.out.println("今年主要是完成指定的需求,bababababa....");
}
}
//B同事的年终总结
static class BConclusion{
//自我介绍
public void introduce(){
System.out.println("尊敬个各位领导/同事,我是B....,接下来是我的年终总结:");
}
//报告内容(经过精心整理)
public void report(){
System.out.println("今年主要是完成指定的需求,在完成需求的同时,也对以前的一些逻辑做重构,降低后期的维护成本,balaba...");
}
}
public static void main(String[] args) {
AConclusion aConclusion = new AConclusion();
aConclusion.introduce();
aConclusion.report();
//领导听完A汇报
System.out.println("我都快睡着了,A这个小伙子表现一般,年终奖降一点吧!");
System.out.println("=========================================================================");
BConclusion bConclusion = new BConclusion();
bConclusion.introduce();
bConclusion.report();
//领导听完B汇报
System.out.println("B这个小伙子做了这么多事情,超出了我的期望值,不错,今年的优秀员工就给他一个名额吧!");
}
}
这段代码就是对以上场景的一个复现,从这里我们发现个问题,都是一样的工作,一个年终奖降了,一个成了优秀员工,怎么会这样呢?就是因为B对工作内容做了大量的修饰,突出了自己对公司的价值,让领导高看一眼(所以一味的老实是不行滴…)。
而B这种描述,就是对A的内容的一种修饰,从上面来看,A、B都有相同的接口,这里我们稍微重构下:
public class EndOfYearConclusion_01 {
//年终总结接口
interface Conclusion{
//自我介绍
public void introduce();
//报告内容(毫无技术含量)
public void report();
}
//A同事的年终总结
static class AConclusion implements Conclusion{
//自我介绍
@Override
public void introduce(){
System.out.println("我是A....");
}
//报告内容(毫无技术含量)
@Override
public void report(){
System.out.println("今年主要是完成指定的需求,bababababa....");
}
}
//B同事的年终总结
static class BConclusion implements Conclusion{
//自我介绍
@Override
public void introduce(){
System.out.println("尊敬个各位领导/同事,我是B....,接下来是我的年终总结:");
}
//报告内容(经过精心整理)
@Override
public void report(){
System.out.println("今年主要是完成指定的需求,在完成需求的同时,也对以前的一些逻辑做重构,降低后期的维护成本,balaba...");
}
}
//领导
static class Leader{
private Conclusion conclusion;
public void listenReport(){
conclusion.introduce();
conclusion.report();
}
public Conclusion getConclusion() {
return conclusion;
}
public void setConclusion(Conclusion conclusion) {
this.conclusion = conclusion;
}
}
public static void main(String[] args) {
Leader leader = new Leader();
leader.setConclusion(new AConclusion());
leader.listenReport();
//领导听完A汇报
System.out.println("我都快睡着了,A这个小伙子表现一般,年终奖降一点吧!");
System.out.println("=========================================================================");
leader.setConclusion(new BConclusion());
leader.listenReport();
//领导听完B汇报
System.out.println("B这个小伙子做了这么多事情,超出了我的期望值,不错,今年的优秀员工就给他一个名额吧!");
}
}
这里让A、B都实现一个总结的接口,并实现两个方法。还添加了一个领导类,来接受到底是轮到哪个同事做年终总结,并可以通过调用listenReport()方法来表示听报告内容。
加入此时来一个经常做报告的C同事,他的报告比B更精彩,此时我们就要让C的总结实现接口类以及两个方法;
如果后面还有更精通作报告的D、E、F、…同事,那怎么办,每个人都要去实现这个接口类以及两个方法;(工作内容都相同,报告内容不同)
年终结束后,A有点丧气,觉得同样的工作,为什么待遇不同呢,于是就请教B或者其他,B告诉他,其实并不是他写得多好,而是借鉴了一些别人的,看别人是怎么写的,自己拿过来稍微的修改了一下。。。A听完后恍然大悟,我擦,居然还有这种操作,那明年我也可以这样搞一搞了(小开心一下^ - ^)。
就这样,来年,大家都对自己的报告做了修饰(实际都知道做的工作一样,就看谁的报告牛皮了,并且还做了备份,为下一年做准备),同时希望自己的主内容不变,来年只需要修改部分修饰信息,还可以继续用。那这个时候我们又要继续对代码进行新一轮的重构了:
public class EndOfYearConclusion_02 {
//年终总结接口
interface Conclusion{
//自我介绍
public void introduce();
//报告内容(毫无技术含量)
public void report();
}
//基本的年终总结模板
static class BaseConclusion implements Conclusion{
//自我介绍
@Override
public void introduce(){
System.out.println("我是XXX");
}
//报告内容(毫无技术含量)
@Override
public void report(){
System.out.println("今年主要是完成指定的需求");
}
}
//这是一个抽象类,主要是被子类继承,并且自身持有了一个总结的引用
static abstract class AbstractConclusion implements Conclusion{
private Conclusion conclusion;
public AbstractConclusion(Conclusion conclusion){
this.conclusion = conclusion;
}
public Conclusion getConclusion() {
return conclusion;
}
}
//A同事的年终总结,
static class AConclusion extends AbstractConclusion{
public AConclusion(Conclusion conclusion) {
super(conclusion);
}
@Override
public void introduce(){
System.out.println("尊敬的各位领导/同事:");
super.getConclusion().introduce();
}
@Override
public void report(){
super.getConclusion().report();
System.out.println("在完成需求的同时,也对以前的一些逻辑做重构,降低后期的维护成本");
}
}
//B同事的年终总结
static class BConclusion extends AbstractConclusion{
public BConclusion(Conclusion conclusion) {
super(conclusion);
}
@Override
public void introduce(){
super.getConclusion().introduce();
System.out.println("接下来是我的年终总结:");
}
@Override
public void report(){
super.getConclusion().report();
System.out.println("在今年的工作中,对自己有了更高的要求,主要体现在对系统的性能做了优化,等等...");
}
}
//领导
static class Leader{
private Conclusion conclusion;
public void listenReport(){
conclusion.introduce();
conclusion.report();
}
public Conclusion getConclusion() {
return conclusion;
}
public void setConclusion(Conclusion conclusion) {
this.conclusion = conclusion;
}
}
public static void main(String[] args) {
BaseConclusion baseConclusion = new BaseConclusion();
Leader leader = new Leader();
leader.setConclusion(new AConclusion(baseConclusion));
leader.listenReport();
System.out.println("今年A这个小伙子进步很大呀,有前途,加点年终奖...");
System.out.println("===================================================");
leader.setConclusion(new BConclusion(baseConclusion));
leader.listenReport();
System.out.println("今年B这个小伙子也很不错,居然超出了预期,继续保留优秀员工...");
System.out.println("===============================================================");
leader.setConclusion(new BConclusion(new AConclusion(baseConclusion)));
leader.listenReport();
System.out.println("哟呵,这个小伙子更不错啊,居然A和B能做的事情他都有做,很好,给他优秀员工,加年终,加薪...");
}
}
以上就是重构后的代码,通过代码我们复现了一个写年终总结的一个大概情形,就是基本内容都一样的时候,可以通过相互借鉴的方式,使得自己的总结报告更加出彩,凸显自己的能力,让领导刮目相看。
总结:
上面重构后的代码结构,符合了装饰模式的定义:动态的给一个对象添加一些额外的职责。(就增加功能来说,装饰模式相比生成子类更加灵活)
装饰模式的优点:
被装饰的类和装饰类可以独立发展自己的逻辑,互不影响;
而且有点类似于代理模式(或者可以认为是一个简单的代理模式的实现);
装饰模式的缺点:
美中不足的是,装饰模式一层套一层,类似与洋葱,如果出现问题,那么势必要一层一层的剥开,这样找起问题来相当麻烦。