設計模式系列之裝飾者模式

前言

本篇文章分爲四個部分:第一部分會舉一個例子引出裝飾者模式,讓讀者對裝飾者模式有個感官上的認識;第二部分會給出裝飾者模式的定義(固然咱們主要不是來背定義,就當作積累專業名詞來記吧,我我的是很不喜歡下定義的);第三部分,我會拿jdk中兩個使用裝飾者模式的例子進行分析,讓讀者在學習模式的同時熟悉一下jdk源碼。第四部分,我會結合裝飾者模式理清楚java I/O各類流之間的關係(說實話,工做中用得最多,可是記了又忘,由於I/O類實在太多)後面學習到其餘框架的時候再補充。java

第一部分

假若有這樣的需求:要求實現只可以讀的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(具體裝飾者):抽象裝飾類的子類
具體的能夠看下面的結構圖:框架

clipboard.png

第三部分 jdk 例子分析

第一部分咱們引出裝飾者模式,ReadOnlyList 只讀List將List給包裝起來,提供了只讀的功能,jdk Collection中也有個相似的實現:
public static <T> List<T> unmodifiableList(List<? extends T> list)dom

讓我來看看它的源碼:ide

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 同步鎖this

讓咱們看源碼:spa

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中的流圖
clipboard.png

clipboard.png

咱們以輸入流來分析,首先InputStream 至關於咱們的抽象組件,FileInputStream、StringBufferInputStream、ByteArrayInputStream都是能夠被裝飾者包裝起來的組件,FilterInputStream至關於抽象裝飾者,PushbackInputStream、BufferedInputStream、DataInputStream和LineNumberInputStream都是具體的裝
飾者

他們能夠這樣用: 一層裝飾一層

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

以下圖所示:
clipboard.png

有了這樣的思路,咱們之後想編寫本身的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();
        }

    }
}
相關文章
相關標籤/搜索