1、前言java
装饰器模式也是一种很是重要的模式,在java以及程序设计中占据着重要的地位。好比java的数据流处理,咱们可能看到数据量通过不一样的类的包装和包裹,最终造成了咱们须要的流,好比说从二进制到字节流再到字符流,这中间其实就是通过了装饰器的处理,在不改变原来数据的基础上,加入属于本身的特征,就像屎在一块蛋糕上加上一些水果等装饰品,这样输出的结果就不一样了,咱们将这种产生相似于洋葱同样层层包裹的数据格式的设计模式称为装饰器模式。apache
那么为何装饰器模式这么神奇呢,几乎可让咱们无穷尽的包裹自身,在计算机中凡是可以无穷尽的重复某一件事情,必然不能设定固定的数据,只能按照用户的随意设置来计算,那么递归的魅力就在此彰显出来了,经过递归能够实现这一点,那么如何递归呢,咱们想到一层套一层的数据结构,就必须在“自身”中包含“自身”;前一个“自身”能够是咱们的子类,由于子类有着父类的全部特色,后一个“自身”就是具备抽象资格的“自身”,正是由于足够抽象使得任何继承与这个抽象类的类都能经过里氏代换原则转换到这个抽象类。实现了递归,咱们只须要中止条件就能够了,中止条件就是用户在main中对元数据包裹的层数,加入新的内容,最终使用最顶层的输出方法将这个结果呈现给咱们。一样的咱们还能够反着看,当递归开始的时候,在最顶层等待下一层的数据,而后使用顶层的方式来封装,而下一层被启动执行到关键步骤时会等待下下一层的数据返回给自身,而后是用本身的方式来封装,就这样一直等待下去,直到最底层的数据(原本就有)获得以后,而后一步步的返回过来,在相应的层次进行相应的封装,最后获得了最终的数据。这就是装饰器模式,全部的类其实最终都是同源(一致性)的,有最终的祖先,以下图所示。编程
2、代码设计模式
上图中,StringDisplay是保存原始数据的,而Border中将父类的引用组合进入自身,造成了递归的必然条件,以后让子类来使用这个引用,从而根据自身的实际状况来进行包装,将原始的数据getRowText(rowID)进行包裹,最终经过同源祖先类的show()方法来实现,这里祖先类display使用了面向抽象编程的模板方法。对比组合模式,咱们能够看到上面的部分仍是很类似的,可是在composite中,都实现了add()方法,经过容器来进行组织,而且使用委托机制来存储全部的有着共同父类的元素,在显示的时候使用了树的深度优先遍历。而在装饰器模式中,咱们使用的递归从上到下,沿着display的指向一点点的走到了底部,而且最终返回了过来。遍历的方式有着类似之处也有着不一样之处。这里要说明的是,建议你们在show的地方打个断点,而后跟踪进去,一点点的看看咱们的程序究竟是怎么组织起来的,只有这样咱们才能理解递归的含义,对装饰器有一个更深层次的认识。数据结构
package designMode.decorator; public abstract class Display { public abstract int getColumns(); public abstract int getRows(); public abstract String getRowText(int rowID); public void show(){ for (int i = 0; i < getRows(); i++) { System.out.println(getRowText(i)); } } }
package designMode.decorator; public class StringDisplay extends Display { String name; public StringDisplay(String name) { this.name = name; } @Override public int getColumns() { return name.getBytes().length; } @Override public int getRows() { return 1; } @Override public String getRowText(int rowID) { if(rowID==0){ return name; }else { return null; } } }
package designMode.decorator; public abstract class Border extends Display { protected Display display; public Border(Display display) { this.display = display; } }
package designMode.decorator; public class SideBorder extends Border { String ch; protected SideBorder(Display display,String ch) { super(display); this.ch = ch; } @Override public int getColumns() { return display.getColumns()+2; } @Override public int getRows() { return display.getRows(); } @Override public String getRowText(int rowID) { return ch + display.getRowText(rowID)+ch; } }
package designMode.decorator; public class FullBorder extends Border { public FullBorder(Display display) { super(display); } @Override public int getColumns() { return display.getColumns()+2; } @Override public int getRows() { return display.getRows()+2; } @Override public String getRowText(int rowID) { if (rowID==0){ return "+"+makeLine("-",display.getColumns())+"+"; }else if(rowID==display.getRows()+1){ return "+"+makeLine("-",display.getColumns())+"+"; }else { return "|"+display.getRowText(rowID-1)+"|"; } } private String makeLine(String ch,int count){ StringBuffer sb = new StringBuffer(); for (int i = 0; i < count; i++) { sb.append(ch); } return sb.toString(); } }
package designMode.decorator; import com.sun.deploy.resources.Deployment_sv; import com.sun.org.apache.bcel.internal.generic.NEW; public class Main { public static void main(String[] args) { Display d1 = new StringDisplay("江疏影"); d1.show(); Display d2 = new SideBorder(d1,"*"); d2.show(); System.out.println("\n"); Display d3 = new FullBorder(d2); d3.show(); System.out.println("\n"); Display d4=new SideBorder(new FullBorder( new FullBorder( new SideBorder( new FullBorder( new StringDisplay("素小暖") ), "#") ) ), "*" ); d4.show(); } }
3、总结app
继承保证了父类和子类的一致性(有共同的方法),委托保证了使用委托的类和被委托对象的一致性。正如Border和Display有着一些相同的方法名称,以及一些委托处理方法。能够看到装饰模式中,保证了装饰边框与被装饰物体的一致性(有共同父类),使用了模板方法,这个方法几乎无处不在呀,一样使用了委托(组合),经过在原始数据上面一层层的包裹,最终获得了咱们想要的输出,有着很是普遍的用处。ide
浅谈设计模式<最通俗易懂的讲解>this