设计模式 一一一 装饰模式

    目的:对对象的相应功能进行增强。
    
    应用:对提供基础功能的类进行个性化增强。
    
    两大要素:
        1,被装饰的类封装于装饰实现类的内部,从而形成对象之间的引用关系。
        2,装饰实现类同样实现了原始接口(原始接口即:被装饰类实现的接口)
    
    说明:
        对象可能被装饰多次,最后的效果就是对象被包装了多层,故装饰器也包装器Wrapper。
        eg:
            DecoratorBase继承且封装了targetObj对象,
            DecoratorOne继承(或封装了)DecoratorBase对象,
            DecoratorOneForA继承(或封装了)DecoratorOne对象,
            即:targetObj对象从里到外被DecoratorBase、DecoratorOne、DecoratorOneForA包装了3层。
        
        
    装饰模式与继承相比的优点:
        装饰类不依赖被装饰的类。原因:在装饰类内部封装的是原始接口,而并不是被装饰的类!

    利用装饰模式装饰原有的类(即被装饰的类)的功能:
        1,编写一个类,并实现原始接口(原始接口即:被装饰的类实现的接口)
        2,在类中定义一个原始接口类型的成员变量,用于封装被装饰的类的实例。
        3,在类中定义构造方法,传入被装饰类的实例。
        4,对于要装饰的方法,改写即可
        5,对于不需要装饰的方法,调用原有的对象的对应方法
        
        
jdk中的装饰模式:
    /**
     * 装饰器FilterInputStream,可以包装InputStream的任何一个子类。
     * 装饰器FilterInputStream封装了被装饰的对象in,且包装器实现了被装饰对象的接口。
     */
    public class FilterInputStream extends InputStream {

        // 被装饰的对象
        protected volatile InputStream in;

        /**
         * 将被装饰的对象传入进来,这里被装饰的对象可以是InputStream的任何一个子类。
         * 换句话说就是,InputStream的任何一个子类都可以被BufferedInputStream包装。
         */
        protected FilterInputStream(InputStream in) {
            this.in = in;
        }

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

    /**
     * 装饰器BufferedInputStream,可以包装InputStream的任何一个子类。
     * 装饰器BufferedInputStream封装了被装饰的对象in,且包装器实现了被装饰对象的接口。
     */
    public class BufferedInputStream extends FilterInputStream {

        // 被装饰的对象,已经封装在父类FilterInputStream中了,故这里不需要重新封装了。

        /**
         * 将被装饰的对象传入进来,这里被装饰的对象可以是InputStream的任何一个子类。
         * 换句话说就是,InputStream的任何一个子类都可以被BufferedInputStream包装。
         */
        public BufferedInputStream(InputStream in) {
            this(in, DEFAULT_BUFFER_SIZE);
        }

        public BufferedInputStream(InputStream in, int size) {
            super(in);
            if (size <= 0) {
                throw new IllegalArgumentException("Buffer size <= 0");
            }
            buf = new byte[size];
        }

        public synchronized int read() throws IOException {
            if (pos >= count) {
                fill();
                if (pos >= count)
                    return -1;
            }
            return getBufIfOpen()[pos++] & 0xff;
        }
    }