研究了一下装饰者模式,分享一下学习心得
在学习这个模式的时候上网查了一下相关的技术博客,大部分都只是实现但是对于这里的一些细节问题很少有去讲,一开始我也只是知道这么写会实现加强一些类的功能。为了彻底搞明白我打断点一步步调试。
首先有这样一个场景
我现在想画一幅人的画像
第一步 准备一张白纸 是空白的
第二部步画一个脸 技术不是很好,画的有点丑
第三步 脸有点黑,加点粉底吧
第四步 带上个假发,也算像个人了
用装饰者模式的实现UML图如下:
一些代码的实现如下
package design.decorator;
/**
* @Description Component是定义一个对象接口,可以给这些对象动态地添加职责
* @Author DJZ-WWS
* @Date 2019/5/9 19:09
*/
public abstract class Component {
public abstract void operation();
}
定义一个被装饰者
package design.decorator;
/**
* @Description 被装饰者
* @Author DJZ-WWS
* @Date 2019/5/9 19:09
*/
public class ConcreteComponent extends Component {
@Override
public void operation() {
System.out.println("最原始的模样什么都没有,啊好丑");
}
}
装饰抽象类
package design.decorator;
/**
* @Description
* @Author DJZ-WWS
* @Date 2019/5/9 19:15
*/
/**
* Decorator,装饰抽象类,继承了Component,从外类来扩展Component类的功能,但对于Component来说, 是无需知道Decorator的存在的
*
*/
public abstract class Decorator extends Component {
protected Component component;
public Component getComponent() {
return component;
}
public void setComponent(Component component) {
this.component = component;
}
@Override
public void operation() {
if (component != null) {
component.operation();
}
}
}
装饰者模式就是采用一个类一个加强的思想,每一个类都对应着对前者功能的叠加这里具体的实现思想最后再说,先看一下每个装饰者
装饰者A
package design.decorator;
/**
* @Description
* @Author DJZ-WWS
* @Date 2019/5/9 19:16
*/
class ConcreteDecoratorA extends Decorator {
@Override
public void operation() {
// 首先运行原Component的operation(),再执行本类的功能,如addedState,相当于对原Component进行了装饰
/**
* 在执行A的时候由于调用了super的方法 被装饰者的父类是Component 根据多肽的特性它会自己执行它自己本身的实现
*/
super.operation();//执行被装饰者
System.out.println("画个一般的脸吧");
}
}
装饰者B
package design.decorator;
/**
* @Description
* @Author DJZ-WWS
* @Date 2019/5/9 19:16
*/
class ConcreteDecoratorB extends Decorator {
@Override
public void operation() {
super.operation();
addedBehavior();
}
public void addedBehavior() {
System.out.print(" 有点丑美化一下吧,擦点粉");
}
}
装饰者C
package design.decorator;
/**
* @Description
* @Author DJZ-WWS
* @Date 2019/5/9 19:16
*/
class ConcreteDecoratorC extends Decorator {
@Override
public void operation() {
super.operation();
System.out.println("带个假发吧,噗,终于像个人了");
}
}
测试类
package design.decorator;
/** 装饰模式客户端调用代码,装饰的过程更像是层层包装,用前面的对象装饰后面的对象
* @Description
* @Author DJZ-WWS
* @Date 2019/5/9 19:11
*/
public class DecoratorClient {
public static void main(String[] args) {
ConcreteComponent concreteComponent = new ConcreteComponent();
ConcreteDecoratorA concreteDecoratorA = new ConcreteDecoratorA();
ConcreteDecoratorB concreteDecoratorB = new ConcreteDecoratorB();
ConcreteDecoratorC concreteDecoratorC = new ConcreteDecoratorC();
/**
* 这里模拟画一幅画,从最开始的什么都没有,到最后的成为一副完美的画
* 多态:编译看父类,执行看子类
*/
concreteDecoratorA.setComponent(concreteComponent);
concreteDecoratorB.setComponent(concreteDecoratorA);
concreteDecoratorC.setComponent(concreteDecoratorB);
concreteDecoratorC.operation();
}
}
输出的结果:
最原始的模样什么都没有,啊好丑
画个一般的脸吧
有点丑美化一下吧
擦点粉带个假发吧,噗,终于像个人了
对结果进行简单的说明
首先明确一点被装饰者是谁
被装饰者是最先被执行的,其次是A,接着是B,接着是C.一次执行他们各自的功能,为什么出出现这个执行顺序?对此我也是在这卡了一下。断点调试了几遍。
首先要明确,A,B,C都是继承了装饰抽象类Decorator。
在图中我们在A中装入的实例是concreteComponent,那么A里面的实例对象就是concreteComponent
同理其他三者里面装的实例对象都是他们对应得对象的实例。
重点来了,当我们走到
concreteDecoratorC.operation();这一步的时候
点进方法进去看一下:
没错,走的c本身的方法,但是紧接着C的operation方法里面又调用了super.operation(),跟着方法走进去,来到了他的父类
因为我们之前在C里面加入的是B的实例当走到component.operation()的 时候,根据多态的特性,执行按照具体的实现执行,这个时候会用B对象执行operation()方法,然后我们走到了B
这时候发现B原来也调用了super.operation(),同样的又来到了父类装饰抽象类
由于之前在B里面设置的实例是A的实例对象,所以它又会被A去执行,依次类推,一直执行到顶层,所以会执行装饰者类,也就是业务最初始的样貌,没有经过任何修饰的初始状态,当他们分别执行完毕的时候,根据栈的执行顺序,后进先出,所以又会继续依次执行A,B,C。最后得到我们控制台的结果。整体的一个大概流程就是这样。
做一个 小小的说明,这个设计模式主要考察队多态的理解,还有就是方法的栈执行顺序,对这一块也不是很了解的可以自己查一查相关的资料。简单的补充一下实现多态的三个核心点
子类继承父类,子类重写父类方法,向上转型。
当然这里的继承也可以改为实现的方式,道理是一样的。
在jdk的IO实现中我们经常见到这样一个写法
DataInputStream in=new DataInputStream(new BufferedInputStream(new FileInputStream("D:\\JAVAworkspace\\ProgramTest\\src\\StreamDemo.java")));
这里的设计思想也是使用到了装饰者模式,这样经过层层包装,每一次都流相关的类进行增强。感兴趣的可以去研究一下IO流的体系。