装饰者模式
动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。
具体被装饰者和抽象装饰类都继承于抽象被装饰者类,继承的是类型,而不是行为。行为来自装饰者和基础组件,或与其他装饰者之间的组合关系。
装饰模式的角色
抽象构件角色(Component):给出一个抽象接口,以规范准备接收附加责任的对象。
具体构件角色(Concrete Component):定义将要接收附加责任的类。
装饰角色(Decorator):持有一个构件(Component)对象的引用,并定义一个与抽象构件接口一致的接口。
具体装饰角色(Concrete Decorator):负责给构件对象“贴上”附加的责任。
装饰模式的特点
装饰对象和真实对象有相同的接口。这样客户端对象就可以以和真实对象相同的方式和装饰对象交互。
装饰对象包含一个真实对象的引用(reference)。
装饰对象接收所有来自客户端的请求,它把这些请求转发给真实的对象。
装饰对象可以在转发这些请求之前或之后附加一些功能。
这样就确保了在运行时,不用修改给定对象的结构就可以在外部增加附加的功能。
代码
1 public class Zhuangxiuzhe { 2 public static void main(String[] args) { 3 Zhuangxiuzhe zhuangxiuzhe=new Zhuangxiuzhe(); 4 Component component=zhuangxiuzhe.new ConcreteComponent(); 5 Component decorator=zhuangxiuzhe.new ConcreteDecorator1(component); 6 decorator.doMethod(); 7 Component decorator2=zhuangxiuzhe.new ConcreteDecorator2(decorator); 8 decorator2.doMethod(); 9 10 } 11 12 interface Component { 13 14 public void doMethod(); 15 16 } 17 18 class ConcreteComponent implements Component { 19 20 public void doMethod() { 21 System.out.println("一般操作"); 22 23 } 24 25 } 26 abstract class Decorator implements Component{ 27 28 protected Component component; 29 public Decorator(Component component){ 30 this.component=component; 31 } 32 33 34 } 35 class ConcreteDecorator1 extends Decorator{ 36 37 public ConcreteDecorator1(Component component) { 38 super(component); 39 40 } 41 public void test1(){ 42 System.out.println("ConcreteDecorator1 额外操作"); 43 } 44 45 public void doMethod() { 46 super.component.doMethod(); 47 test1(); 48 } 49 } 50 class ConcreteDecorator2 extends Decorator{ 51 52 public ConcreteDecorator2(Component component) { 53 super(component); 54 55 } 56 57 public void doMethod() { 58 super.component.doMethod(); 59 test2(); 60 } 61 62 public void test2(){ 63 System.out.println("ConcreteDecorator2 额外操作"); 64 } 65 } 66 67 68 }
执行结果
一般操作
ConcreteDecorator1 额外操作
一般操作
ConcreteDecorator1 额外操作
ConcreteDecorator2 额外操作
突然发现装修者模式跟责任链模式有点相同,自身都引用了抽象类,这样可以调用传入的包装类
区别在于功能上:责任链强调的是请求由谁来处理,而装修者模式则是对引入的对象的现有功能进行包装,增强改变
Java IO中的装饰模式
在IO中,具体构件角色是节点流,装饰角色是过滤流。
FilterInputStream和FilterOutputStream是装饰角色,而其他派生自它们的类则是具体装饰角色。
我们来看看代码
抽象角色类InputStream
1 public abstract class InputStream implements Closeable { 2 3 4 //实现了read等方法 5 public int read(byte b[]) throws IOException { 6 return read(b, 0, b.length); 7 } 8 9 }
具体角色类FileInputStream
1 public 2 class FileInputStream extends InputStream{ 3 4 5 }
抽象包装类FilterInputStream
1 public 2 class FilterInputStream extends InputStream { 3 /** 4 * The input stream to be filtered. 5 */ 6 protected volatile InputStream in; 7 8 9 protected FilterInputStream(InputStream in) { 10 this.in = in; 11 } 12 13 public int read() throws IOException { 14 return in.read(); 15 } 16 17 18 }
具体包装类BufferedInputStream
1 public 2 class BufferedInputStream extends FilterInputStream { 3 4 public BufferedInputStream(InputStream in) { 5 this(in, defaultBufferSize); 6 } 7 8 //完成了设置抽象角色类的映射 9 public BufferedInputStream(InputStream in, int size) { 10 super(in); 11 if (size <= 0) { 12 throw new IllegalArgumentException("Buffer size <= 0"); 13 } 14 buf = new byte[size]; 15 } 16 17 //read方法中调用fill() 18 public synchronized int read() throws IOException { 19 if (pos >= count) { 20 fill(); 21 if (pos >= count) 22 return -1; 23 } 24 return getBufIfOpen()[pos++] & 0xff; 25 } 26 private void fill() throws IOException { 27 byte[] buffer = getBufIfOpen(); 28 if (markpos < 0) 29 pos = 0; /* no mark: throw away the buffer */ 30 else if (pos >= buffer.length) /* no room left in buffer */ 31 if (markpos > 0) { /* can throw away early part of the buffer */ 32 int sz = pos - markpos; 33 System.arraycopy(buffer, markpos, buffer, 0, sz); 34 pos = sz; 35 markpos = 0; 36 } else if (buffer.length >= marklimit) { 37 markpos = -1; /* buffer got too big, invalidate mark */ 38 pos = 0; /* drop buffer contents */ 39 } else { /* grow buffer */ 40 int nsz = pos * 2; 41 if (nsz > marklimit) 42 nsz = marklimit; 43 byte nbuf[] = new byte[nsz]; 44 System.arraycopy(buffer, 0, nbuf, 0, pos); 45 if (!bufUpdater.compareAndSet(this, buffer, nbuf)) { 46 // Can‘t replace buf if there was an async close. 47 // Note: This would need to be changed if fill() 48 // is ever made accessible to multiple threads. 49 // But for now, the only way CAS can fail is via close. 50 // assert buf == null; 51 throw new IOException("Stream closed"); 52 } 53 buffer = nbuf; 54 } 55 count = pos; 56 int n = getInIfOpen().read(buffer, pos, buffer.length - pos); 57 if (n > 0) 58 count = n + pos; 59 } 60 61 62 }
fill()方法中除了自身操作外,我们看到了 int n = getInIfOpen().read(buffer, pos, buffer.length - pos);
1 private InputStream getInIfOpen() throws IOException { 2 InputStream input = in; 3 if (input == null) 4 throw new IOException("Stream closed"); 5 return input; 6 }
在看看getInIfOpen()方法,我们就明白了 整个的过程
参考地址:
http://www.cnblogs.com/mengdd/archive/2013/02/12/2910302.html
http://blog.csdn.net/cai1213/article/details/8003445
http://xubindehao.iteye.com/blog/474636
《JAVA与模式》之装修者模式