首页 > 代码库 > 《JAVA与模式》之装修者模式

《JAVA与模式》之装修者模式

装饰者模式

动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。

具体被装饰者和抽象装饰类都继承于抽象被装饰者类,继承的是类型,而不是行为。行为来自装饰者和基础组件,或与其他装饰者之间的组合关系。

装饰模式的角色

  抽象构件角色(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 public2 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