装饰模式(Decorator)就是使用被装饰的一个子类的实例,在客户端将这个子类的实例委托给装饰类。装饰模式是结成关系的一个替代方案。
装饰模式以对客户端透明的方式增添了对象的功能,其在与动态的给对象添加了责任,当然这里的继承便是静态的。
其中重要的地方时装饰对象和真实对象有相同的接口,这样客户端就可以和真是对象一样的交互方式和装饰对象交互,然后装饰对象把所有从客户端接收过来的请求全部转发给真是对象,然后在返还给客户端,这样装饰对象就可以再转发前或者以后添加一些附加功能而不影响对真是对象的操作,这样在不改变原有类的基础上,可以实现对于原有类的这种额外功能的实现,增强了程序的复用性。
同时装饰模式比继承好的地方就是,装饰模式可以动态的对已经存在的类进行任意的组合,实现想要的功能,而继承是静态的实现,不能改变原有类的实现,如果要添加更多的功能,只有添加更多的派生类来实现。
下面以员工加工画为例子实现装饰者模式
抽象组件Work.java
package decorator; public abstract class Work { public abstract void painting(); }
装饰者1Work.java
package decorator; public class WorkerOne extends Work { @Override public void painting() { System.out.println("1号员工画画"); } }装饰者3Work.java
package decorator; public class WorkerThree extends Work { //被装饰者 private Work work; public WorkerThree(Work work) { this.work = work; } private WorkerThree() {} @Override public void painting() { System.out.println("3号员工上画框前前的准备工作。"); //被装饰者做的职责 work.painting(); //装饰者做的职责 System.out.println("3号员工上画框。"); } }装饰者2Work.java
package decorator; public class WorkerTwo extends Work { //被装饰者 private Work work; public WorkerTwo(Work work) { this.work = work; } private WorkerTwo() {} @Override public void painting() { System.out.println("2号员工给画上颜色前的准备工作。"); //被装饰者做的职责 work.painting(); //装饰者做的职责 System.out.println("2号员工给画上好了颜色。"); } }测试类
package decorator; public class Test { public static void main(String[] args) { System.out.println("*****只做画画工作*****"); WorkerOne workerOne = new WorkerOne(); workerOne.painting(); System.out.println("*****只做上色工作*****"); WorkerTwo workerTwo = new WorkerTwo(workerOne); workerTwo.painting(); System.out.println("****做全部工作*****"); WorkerThree workerThree = new WorkerThree(workerTwo); workerThree.painting(); } }适用装饰者模式场合: 装饰模式模式可以说是代理模式的一个特殊应用,甚至可以认为他们结构上是一致的;只是他们关心地方不同,代理模式关心对象方法的预处理和善后处理,装饰模式关心对象方法的“增强”(注意:不是“增加”)或“减弱”。 责任链模式将多个处理对象聚合成一条链状,被处理对象直接交由链头处理,它会在链中被依次传递下去直到处理完成或到达最后一个处理对象为止。责任链模式可以将请求和处理分开,但是要注意链过长时的性能问题和链中节点数量问题。 策略模式提供了一种动态改变对象方法行为的途径;它的实现是将算法封装起来,对象中使用Setter(或构造函数)接收具体算法对象,然后在对象方法被调用时执行接收到的具体算法。 javaIO就是一个典型的装饰者的例子,我们可以直接使用
将输入流字符改为小写LowerCaseInputStream.java
package javaIO; import java.io.FilterInputStream; import java.io.IOException; import java.io.InputStream; public class LowerCaseInputStream extends FilterInputStream { protected LowerCaseInputStream(InputStream in) { super(in); } public int read() throws IOException{ int i = super.read(); return i==-1?i:Character.toLowerCase(i); } public int read(byte[] b,int off,int len) throws IOException{ int result = super.read(b, off, len); for(int i=off;i<off+result;i++){ b[i] = (byte)Character.toLowerCase(b[i]); } return result; } }测试类
package javaIO; import java.io.BufferedInputStream; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; public class Test { public static void main(String[] args) throws IOException { int c; try { InputStream in = new LowerCaseInputStream( new BufferedInputStream( new FileInputStream("test.txt"))); while((c=in.read())>=0){ System.out.print((char)c); } // byte[] b=new byte[3]; // while((c=in.read(b,0,3))>=0){ // for(int i=0;i<3;i++){ // System.out.print((char)b[i]); // } // } } catch (FileNotFoundException e) { e.printStackTrace(); } } }