android和设计模式随谈之装饰模式

1、装饰模式。

  • 装饰模式的现实生活理解,例如现在有一扇窗户,窗户只有普通边框和玻璃,有一天我需要把这散窗口换成有花纹边框的窗户。这个时候怎么办呢?有2种方式,第一种去买一些装饰花边,对窗户的边框进行装饰一下;第二种换掉目前的窗户,买一扇带花纹边框的窗户,替换过程有两种代价,一是替换后花的金钱(对应计算机资源)肯定会更多,并且换窗户还浪费人;第二种如果市场没有这样窗户,那么工厂需要增加一条带花纹边框的生产线。又过了一段时间,突然感觉带花纹边框的窗口不好看了,如果是装饰上去的,直接拆掉装饰花纹即可;如果是购买新的那扇(对应继承)的则又需要重新购买替换,再次替换代价是金钱,如果使用之前被替换的那扇不带花纹的,代价就是这扇被拆掉的窗口存放这么长时间,占据了很大的空间(对应内存)。
  • 如果某一天我又需要边框带花纹,窗户玻璃上上半部分需要有防曝光功能,这样怎么办呢?如果采用装饰,则直接购买花纹贴纸、防爆膜,装饰上窗口即可,代价小、时间快、简单、便捷。如果是采用继承加工,那么又需要增加生产线,生产线上增加花纹边框、上面防曝光等工序,这样会带来大量资源和时间浪费。
  • 如果窗户后续需要增加10个新功能功或特点呢?装饰模式的话,直接一步一步增加上去即可,不需要的时候直接去掉;而继承生产的话会被这种变化拖死,代理巨大资源浪费。
  • 装饰模式和继承,都是为了扩张对象功能。
  • 装饰模式灵活性非常大,并且会降低依耐性,但是因为一种功能就要向被类中增加一个对象,装饰对象多了之后被装饰的类结构会复杂化,各个装饰对象也不方便管理。
  • 装饰模式在android中的应用,android整个APP的入口为ThreadActivity类,ThreadActivity中有一个main静态方法,android是基于JAVA的,因此入口为main函数,因此ThreadActivity是App的入口。ThreadActivity中通过mainLooper创建了主线程的Handler。
  • 再说说android中的装饰模式使用,Acitivity ->ContextThemWrapper ->ContextWrapper -> Context,ContextWrapper 的构造函数参数为Context。而Context的所有方法的唯一实现为ContextImpl,因此ContextWrapper 的构造函数传过来的为ContextImpl。而ContextWrapper的各种方法的调用,其实是调用的ContextImpl中的方法。相当于,ContextWrapper 中的各种功能的提供均是ContextImpl装饰后提供的,因此Activity、Serviec、Broadcast中的各种方法调用其实调用ContextImpl中的方法。这里就很好了反应了装饰模式。ContextImpl的创建时在ThreadActivity中。

  • 装饰模式在JAVA中的应用,即是JAVA的IO操作。

  • FilterInputStream:FilterInputStream构造函数会传入一个装饰对象inputstream,而FilterInputStream中所有的操作都是调用的传进来的inputstream对象方法的调用,本类即是I/O装饰的父类。其子类BufferedInputStream ,即是在FilterInputStream的功能上增加了一个缓冲功能,这样BufferedInputStream 既有了I/O功能,又有了缓冲功能。

    这是字节输入流部分装饰器模式的核心。是我们在装饰器模式中的Decorator对象,主要完成对其它流装饰的基本功能。下面是它的源代码:
    package java.io;

//该类对被装饰的流进行基本的包裹。不增加额外的功能。
//客户在需要的时候可以覆盖相应的方法。具体覆盖可以在ByteInputStream中看到!

public class FilterInputStream extends InputStream {
    
    
    protected volatile InputStream in;                       //将要被装饰的字节输入流

    protected FilterInputStream(InputStream in) {   //通过构造方法传入此被装饰的流
                   this.in = in;
    }
         //装饰器的代码特征:被装饰的对象一般是装饰器的成员变量
         //上面几行可以看出。

         //下面这些方法,完成最小的装饰――0装饰,只是调用被装饰流的方法而已

    public int read() throws IOException {
                   return in.read();
    }

    public int read(byte b[]) throws IOException {
                   return read(b, 0, b.length);
    }

    public int read(byte b[], int off, int len) throws IOException {
                   return in.read(b, off, len);
    }

    public long skip(long n) throws IOException {
                   return in.skip(n);
    }

    public int available() throws IOException {
                   return in.available();
    }

    public void close() throws IOException {
                   in.close();
    }

    public synchronized void mark(int readlimit) {
                   in.mark(readlimit);
    }

    public synchronized void reset() throws IOException {
                   in.reset();
    }

    public boolean markSupported() {
                   return in.markSupported();
}

//以上的方法,都是通过调用被装饰对象in完成的。没有添加任何额外功能
//装饰器模式中的Decorator对象,不增加被装饰对象的功能。
//它是装饰器模式中的核心。更多关于装饰器模式的理论请阅读博客中的文章。
}

以上分析了所有字节输入流的公共父类InputStream和装饰器类FilterInputStream类。他们是装饰器模式中两个重要的类。更多细节请阅读博客中装饰器模式的文章。下面将讲解一个具体的流ByteArrayInputStream,不过它是采用适配器设计模式。

4 BufferedInputStream
4.2 BufferedInputStream源代码分析

package java.io;

import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;

//该类主要完成对被包装流,加上一个缓存的功能
public class BufferedInputStream extends FilterInputStream {
    
    
    private static int defaultBufferSize = 8192;                                      //默认缓存的大小
    protected volatile byte buf[];                                                            //内部的缓存
    protected int count;                                                                                            //buffer的大小
    protected int pos;                                                                               //buffer中cursor的位置
    protected int markpos = -1;                                                                     //mark的位置
    protected int marklimit;                                                                            //mark的范围

//原子性更新。和一致性编程相关
    private static final
        AtomicReferenceFieldUpdater<BufferedInputStream, byte[]> bufUpdater =
        AtomicReferenceFieldUpdater.newUpdater (BufferedInputStream.class,  byte[].class, "buf");

    private InputStream getInIfOpen() throws IOException {  //检查输入流是否关闭,同时返回被包装流
        InputStream input = in;
         if (input == null)    throw new IOException("Stream closed");
        return input;
    }

    private byte[] getBufIfOpen() throws IOException {                       //检查buffer的状态,同时返回缓存
        byte[] buffer = buf;
         if (buffer == null)   throw new IOException("Stream closed");            //不太可能发生的状态
        return buffer;
    }

    public BufferedInputStream(InputStream in) {                               //构造器
                   this(in, defaultBufferSize);                                                              //指定默认长度的buffer
    }

    public BufferedInputStream(InputStream in, int size) {                           //构造器
                   super(in);
        if (size <= 0) {                                                                                         //检查输入参数
            throw new IllegalArgumentException("Buffer size <= 0");
        }
                   buf = new byte[size];                                                                     //创建指定长度的buffer
    }

         //从流中读取数据,填充如缓存中。
    private void fill() throws IOException {
        byte[] buffer = getBufIfOpen();                            //得到buffer
         if (markpos < 0)
             pos = 0;                                                             //mark位置小于0,此时pos为0
         else if (pos >= buffer.length)                               //pos大于buffer的长度
             if (markpos > 0) {        
                   int sz = pos - markpos;                            //
                   System.arraycopy(buffer, markpos, buffer, 0, sz);
                   pos = sz;
                   markpos = 0;
             } else if (buffer.length >= marklimit) {                 //buffer的长度大于marklimit时,mark失效
                   markpos = -1;                                                   //
                   pos = 0;                                                             //丢弃buffer中的内容
             } else {                                                                         //buffer的长度小于marklimit时对buffer扩容
                   int nsz = pos * 2;
                   if (nsz > marklimit)           nsz = marklimit;//扩容为原来的2倍,太大则为marklimit大小
                   byte nbuf[] = new byte[nsz];                    
                   System.arraycopy(buffer, 0, nbuf, 0, pos);        //将buffer中的字节拷贝如扩容后的buf中
                if (!bufUpdater.compareAndSet(this, buffer, nbuf)) {
                                                                                                                         //在buffer在被操作时,不能取代此buffer
                    throw new IOException("Stream closed");
                }
                buffer = nbuf;                                                               //将新buf赋值给buffer
             }
        count = pos;
         int n = getInIfOpen().read(buffer, pos, buffer.length - pos);
        if (n > 0)     count = n + pos;
    }

    public synchronized int read() throws IOException { //读取下一个字节
         if (pos >= count) {                                                                 //到达buffer的末端
             fill();                                                                    //就从流中读取数据,填充buffer
             if (pos >= count)  return -1;                                //读过一次,没有数据则返回-1
         }
         return getBufIfOpen()[pos++] & 0xff;                           //返回buffer中下一个位置的字节
    }

    private int read1(byte[] b, int off, int len) throws IOException {                 //将数据从流中读入buffer中
         int avail = count - pos;                                                                             //buffer中还剩的可读字符
         if (avail <= 0) {                                                                                        //buffer中没有可以读取的数据时
             if (len >= getBufIfOpen().length && markpos < 0) {             //将输入流中的字节读入b中
                   return getInIfOpen().read(b, off, len);
             }
             fill();                                                                                                //填充
             avail = count - pos;
             if (avail <= 0) return -1;
         }
         int cnt = (avail < len) ? avail : len;                                                  //从流中读取后,检查可以读取的数目
         System.arraycopy(getBufIfOpen(), pos, b, off, cnt);            //将当前buffer中的字节放入b的末端
         pos += cnt;
         return cnt;
    }


    public synchronized int read(byte b[], int off, int len)throws IOException {
        getBufIfOpen();                                                                             // 检查buffer是否open
        if ((off | len | (off + len) | (b.length - (off + len))) < 0) {            //检查输入参数是否正确
             throw new IndexOutOfBoundsException();
         } else if (len == 0) {
            return 0;
        }
         int n = 0;
        for (;;) {
            int nread = read1(b, off + n, len - n);
            if (nread <= 0)     return (n == 0) ? nread : n;
            n += nread;
            if (n >= len)     return n;
            // if not closed but no bytes available, return
            InputStream input = in;
            if (input != null && input.available() <= 0)     return n;
        }
    }


    public synchronized long skip(long n) throws IOException {
        getBufIfOpen();                                        // 检查buffer是否关闭
         if (n <= 0) {    return 0;      }                 //检查输入参数是否正确
         long avail = count - pos;                    //buffered中可以读取字节的数目
        if (avail <= 0) {                                          //可以读取的小于0,则从流中读取
            if (markpos <0)  return getInIfOpen().skip(n); //mark小于0,则mark在流中      
            fill();                                  // 从流中读取数据,填充缓冲区。
            avail = count - pos;                                   //可以读的取字节为buffer的容量减当前位置
            if (avail <= 0)     return 0;
        }       
        long skipped = (avail < n) ? avail : n;      
        pos += skipped;                                       //当前位置改变
        return skipped;
    }

    public synchronized int available() throws IOException {
                   return getInIfOpen().available() + (count - pos);                 
    }
         //该方法不会block!返回流中可以读取的字节的数目。
         //该方法的返回值为缓存中的可读字节数目加流中可读字节数目的和

    public synchronized void mark(int readlimit) {  //当前位置处为mark位置
         marklimit = readlimit;
         markpos = pos;
    }

    public synchronized void reset() throws IOException {
        getBufIfOpen(); // 缓冲去关闭了,肯定就抛出异常!程序设计中经常的手段
                   if (markpos < 0)     throw new IOException("Resetting to invalid mark");
                   pos = markpos;
    }

    public boolean markSupported() {           //该流和ByteArrayInputStream一样都支持mark
                   return true;
    }

         //关闭当前流同时释放相应的系统资源。
    public void close() throws IOException {
        byte[] buffer;
        while ( (buffer = buf) != null) {
            if (bufUpdater.compareAndSet(this, buffer, null)) {
                InputStream input = in;
                in = null;
                if (input != null)    input.close();
                return;
            }
            // Else retry in case a new buf was CASed in fill()
        }
    }
}



猜你喜欢

转载自blog.csdn.net/wangqiubo2010/article/details/79478554