内容简介:本篇文章分为四个部分:第一部分会举一个例子引出装饰者模式,让读者对装饰者模式有个感官上的认识;第二部分会给出装饰者模式的定义(当然我们主要不是来背定义,就当做积累专业名词来记吧,我个人是很不喜欢下定义的);第三部分,我会拿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(); } } }
以上所述就是小编给大家介绍的《设计模式系列之装饰者模式》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 设计模式——订阅模式(观察者模式)
- 设计模式-简单工厂、工厂方法模式、抽象工厂模式
- java23种设计模式-门面模式(外观模式)
- 设计模式-享元设计模式
- Java 设计模式之工厂方法模式与抽象工厂模式
- JAVA设计模式之模板方法模式和建造者模式
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Head First Java(第二版·中文版)
Kathy Sierra,Bert Bates 著、杨尊一 编译 张然等 改编 / 杨尊一 / 中国电力出版社 / 2007-2 / 79.00元
《Head First Java》是本完整的面向对象(object-oriented,OO)程序设计和Java的学习指导。此书是根据学习理论所设计的,让你可以从学习程序语言的基础开始一直到包括线程、网络与分布式程序等项目。最重要的,你会学会如何像个面向对象开发者一样去思考。 而且不只是读死书,你还会玩游戏、拼图、解谜题以及以意想不到的方式与Java交互。在这些活动中,你会写出一堆真正的Jav......一起来看看 《Head First Java(第二版·中文版)》 这本书的介绍吧!