前言

本篇文章分为四个部分:第一部分会举一个例子引出装饰者模式,让读者对装饰者模式有个感官上的认识;第二部分会给出装饰者模式的定义(当然我们主要不是来背定义,就当做积累专业名词来记吧,我个人是很不喜欢下定义的);第三部分,我会拿jdk中两个使用装饰者模式的例子进行分析,让读者在学习模式的同时熟悉一下jdk源码。第四部分,我会结合装饰者模式理清楚java I/O各种流之间的关系(说实话,工作中用得最多,但是记了又忘,因为I/O类实在太多)后面学习到其他框架的时候再补充。

第一部分

假如有这样的需求:要求实现只能够读的List,要是你来完成这个任务你会如何做?
看下面代码实现:

package decorate;import java.util.*;public class ReadOnlyList<E> implements List<E>{    private List<E> target;    public ReadOnlyList(List<E> target) {        super();        this.target = target;    }    @Override    public int size() {        return target.size();    }    @Override    public boolean isEmpty() {        return target.isEmpty();    }    @Override    public boolean contains(Object o) {        return target.contains(o);    }    @Override    public Iterator<E> iterator() {        return target.iterator();    }    @Override    public Object[] toArray() {        return target.toArray();    }    @Override    public <T> T[] toArray(T[] a) {        return target.toArray(a);    }    @Override    public boolean add(E e) {        throw new RuntimeException("only read");    }    @Override    public boolean remove(Object o) {        throw new RuntimeException("only read");    }    @Override    public boolean containsAll(Collection<?> c) {        return target.containsAll(c);    }    @Override    public boolean addAll(Collection<? extends E> c) {        throw new RuntimeException("only read");    }    @Override    public boolean removeAll(Collection<?> c) {        throw new RuntimeException("only read");    }    @Override    public boolean retainAll(Collection<?> c) {        throw new RuntimeException("only read");    }    @Override    public void clear() {        throw new RuntimeException("only read");    }    @Override    public boolean addAll(int index, Collection<? extends E> c) {        throw new RuntimeException("only read");    }    @Override    public E get(int index) {        return target.get(index);    }    @Override    public E set(int index, E element) {        throw new RuntimeException("only read");    }    @Override    public void add(int index, E element) {        throw new RuntimeException("only read");    }    @Override    public E remove(int index) {        throw new RuntimeException("only read");    }    @Override    public int indexOf(Object o) {        return target.indexOf(o);    }    @Override    public int lastIndexOf(Object o) {        return target.lastIndexOf(o);    }    @Override    public ListIterator<E> listIterator() {        return target.listIterator();    }    @Override    public ListIterator<E> listIterator(int index) {        return target.listIterator(index);    }    @Override    public List<E> subList(int fromIndex, int toIndex) {        return target.subList(fromIndex, toIndex);    }}

这里的set,add,remove和addAll等操作都被限制了,只能够读。
测试类

package decorate;import java.util.ArrayList;import java.util.List;public class ReadOnlyListMain {    public static void main(String[] args) {        List<String> list = new ArrayList<>();        list.add("设计模式");        list.add("装饰者模式");        list.add("工厂模式");        ReadOnlyList onlyList = new ReadOnlyList<>(list);//        onlyList.add("只能读啦"); // 会报错只读异常        System.out.println(onlyList.size()); // 可以正确运行    }}

第二部分 定义

Component(抽象组件): 是具体组件和抽象装饰类的共同父类,声明了在具体组件中实现的方法。比如第一部分的List
ConcreteComponent(具体组件): 抽象组件的子类,实现抽象组件的方法,装饰器可以给他加新的功能。比如ReadOnlyList
Decorator(抽象装饰者): 抽象组件的子类,用来装饰具体组件或者装饰其他装饰组件
ConcreteDecorator(具体装饰者):抽象装饰类的子类
具体的可以看下面的结构图:

第三部分 jdk 例子分析

第一部分我们引出装饰者模式,ReadOnlyList 只读List将List给包装起来,提供了只读的功能,jdk Collection中也有个类似的实现:
public static <T> List<T> unmodifiableList(List<? extends T> list)

让我来看看它的源码:

public static <T> List<T> unmodifiableList(List<? extends T> list) {        return (list instanceof RandomAccess ?                new UnmodifiableRandomAccessList<>(list) :                new UnmodifiableList<>(list));    }

我们进入 UnmodifiableList

 /**     * @serial include     */    static class UnmodifiableList<E> extends UnmodifiableCollection<E>                                  implements List<E> {        private static final long serialVersionUID = -283967356065247728L;        final List<? extends E> list;        UnmodifiableList(List<? extends E> list) {            super(list);            this.list = list;        }        public boolean equals(Object o) {return o == this || list.equals(o);}        public int hashCode()           {return list.hashCode();}        public E get(int index) {return list.get(index);}        public E set(int index, E element) {            throw new UnsupportedOperationException();        }        public void add(int index, E element) {            throw new UnsupportedOperationException();        }        public E remove(int index) {            throw new UnsupportedOperationException();        }        public int indexOf(Object o)            {return list.indexOf(o);}        public int lastIndexOf(Object o)        {return list.lastIndexOf(o);}        public boolean addAll(int index, Collection<? extends E> c) {            throw new UnsupportedOperationException();        }        @Override        public void replaceAll(UnaryOperator<E> operator) {            throw new UnsupportedOperationException();        }        @Override        public void sort(Comparator<? super E> c) {            throw new UnsupportedOperationException();        }        public ListIterator<E> listIterator()   {return listIterator(0);}        public ListIterator<E> listIterator(final int index) {            return new ListIterator<E>() {                private final ListIterator<? extends E> i                    = list.listIterator(index);                public boolean hasNext()     {return i.hasNext();}                public E next()              {return i.next();}                public boolean hasPrevious() {return i.hasPrevious();}                public E previous()          {return i.previous();}                public int nextIndex()       {return i.nextIndex();}                public int previousIndex()   {return i.previousIndex();}                public void remove() {                    throw new UnsupportedOperationException();                }                public void set(E e) {                    throw new UnsupportedOperationException();                }                public void add(E e) {                    throw new UnsupportedOperationException();                }                @Override                public void forEachRemaining(Consumer<? super E> action) {                    i.forEachRemaining(action);                }            };        }        public List<E> subList(int fromIndex, int toIndex) {            return new UnmodifiableList<>(list.subList(fromIndex, toIndex));        }                private Object readResolve() {            return (list instanceof RandomAccess                    ? new UnmodifiableRandomAccessList<>(list)                    : this);        }    }

你们发现了啥,没错,就是它:addAll、replaceAll和sort等都抛出 UnsupportedOperationException异常,说明只支持读。

还没结束,再举个例子,Collections中还有将线程不安全的集合转换成线程安全的集合synchronizedList,也就是使用装饰者模式,本质上就是在方法加上synchronized 同步锁

让我们看源码:

public static <T> List<T> synchronizedList(List<T> list) {        return (list instanceof RandomAccess ?                new SynchronizedRandomAccessList<>(list) :                new SynchronizedList<>(list));    }

老规矩,进入SynchronizedList

/**     * @serial include     */    static class SynchronizedList<E>        extends SynchronizedCollection<E>        implements List<E> {        private static final long serialVersionUID = -7754090372962971524L;        final List<E> list;        SynchronizedList(List<E> list) {            super(list);            this.list = list;        }        SynchronizedList(List<E> list, Object mutex) {            super(list, mutex);            this.list = list;        }        public boolean equals(Object o) {            if (this == o)                return true;            synchronized (mutex) {return list.equals(o);}        }        public int hashCode() {            synchronized (mutex) {return list.hashCode();}        }        public E get(int index) {            synchronized (mutex) {return list.get(index);}        }        public E set(int index, E element) {            synchronized (mutex) {return list.set(index, element);}        }        public void add(int index, E element) {            synchronized (mutex) {list.add(index, element);}        }        public E remove(int index) {            synchronized (mutex) {return list.remove(index);}        }        public int indexOf(Object o) {            synchronized (mutex) {return list.indexOf(o);}        }        public int lastIndexOf(Object o) {            synchronized (mutex) {return list.lastIndexOf(o);}        }        public boolean addAll(int index, Collection<? extends E> c) {            synchronized (mutex) {return list.addAll(index, c);}        }        public ListIterator<E> listIterator() {            return list.listIterator(); // Must be manually synched by user        }        public ListIterator<E> listIterator(int index) {            return list.listIterator(index); // Must be manually synched by user        }        public List<E> subList(int fromIndex, int toIndex) {            synchronized (mutex) {                return new SynchronizedList<>(list.subList(fromIndex, toIndex),                                            mutex);            }        }        @Override        public void replaceAll(UnaryOperator<E> operator) {            synchronized (mutex) {list.replaceAll(operator);}        }        @Override        public void sort(Comparator<? super E> c) {            synchronized (mutex) {list.sort(c);}        }private Object readResolve() {            return (list instanceof RandomAccess                    ? new SynchronizedRandomAccessList<>(list)                    : this);        }

嘿嘿,我们现在已经学会从设计模式的角度看jdk源码啦,开心。

第四部分 Java I/O流中的装饰者模式

我们来看看Java I/O中的流图

我们以输入流来分析,首先InputStream 相当于我们的抽象组件,FileInputStream、StringBufferInputStream、ByteArrayInputStream都是可以被装饰者包装起来的组件,FilterInputStream相当于抽象装饰者,PushbackInputStream、BufferedInputStream、DataInputStream和LineNumberInputStream都是具体的装
饰者

他们可以这样用: 一层装饰一层

    InputStream ip = new DataInputStream(new BufferedInputStream(new FileInputStream(new File("/file_path"))));

如下图所示:

有了这样的思路,我们以后想编写自己的I/O,给流增加新的特性,我们就可以继承FilterInputStream,

package decorate;import java.io.FilterInputStream;import java.io.IOException;import java.io.InputStream;/** * 将输入的流内所有的大写字符转成小写字符 */public class LowerCaseInputStream extends FilterInputStream{    public LowerCaseInputStream(InputStream in) {        super(in);    }    @Override    public int read() throws IOException {        int c = super.read();        if (c == -1) {            return c;        } else {            return Character.toLowerCase((char)c);        }    }    @Override    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((char)b[i]);        }        return result;    }}

测试类:把文件路径替换成你自己的路径

package decorate;import java.io.*;/** * 测试类 */public class MyInputStreamTest {    public static void main(String[] args) {        int c;        try {            InputStream in = new LowerCaseInputStream(new BufferedInputStream(new FileInputStream("file_path")));            while((c = in.read()) >= 0) {                System.out.println((char)c);            }        } catch (IOException e) {            e.printStackTrace();        }    }}