设计模式系列之装饰者模式

栏目: 后端 · 发布时间: 4年前

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

前言

本篇文章分为四个部分:第一部分会举一个例子引出装饰者模式,让读者对装饰者模式有个感官上的认识;第二部分会给出装饰者模式的定义(当然我们主要不是来背定义,就当做积累专业名词来记吧,我个人是很不喜欢下定义的);第三部分,我会拿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();
        }

    }
}

以上所述就是小编给大家介绍的《设计模式系列之装饰者模式》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

The Nature of Code

The Nature of Code

Daniel Shiffman / The Nature of Code / 2012-12-13 / GBP 19.95

How can we capture the unpredictable evolutionary and emergent properties of nature in software? How can understanding the mathematical principles behind our physical world help us to create digital w......一起来看看 《The Nature of Code》 这本书的介绍吧!

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换