本文最后更新于 1246 天前,其中的信息可能已经有所发展或是发生改变。
装饰器模式
定义
通过将对象放入包含行为的特殊封装对象中来为原对象绑定新的行为。
实现方式
IA 需要增强的功能,对应的接口
public interface IA {
void func();
}
A 待增强的类
public class A implements IA {
@Override
public void func() {
}
}
ADecorator 装饰器,对功能增强
public class ADecorator implements IA {
private IA ia;
public ADecorator(IA ia) {
this.ia = ia;
}
@Override
public void func() {
// 增强...
ia.func();
// 增强...
}
}
JavaIO里如何使用的装饰器
DataInputStream为什么继承FileInputStream,而不是直接组合InputStream?
为了让DataInputStream只重写InputStream中,自己关注的方法。
在FileInputStream中,对继承自InputStream的方法都重写了,并且内部调用的是组合的InputStream,而不是父类的方法。那为什么不直接用父类的方法呢?原因是组合的InputStream是外部传进来的,运用了多态,这个InputStream可能是其子类,包含额外对数据加工的操作。
为了达到此目的,需要对InputStream的所有方法进行重写,这部分重复的工作就交给了FileInputStream。
优点
- 你无需创建新子类即可扩展对象的行为。
- 你可以在运行时添加或删除对象的功能。
- 你可以用多个装饰封装对象来组合几种行为。
- 单一职责原则。 你可以将实现了许多不同行为的一个大类拆分为多个较小的类。
缺点
- 在封装器栈中删除特定封装器比较困难。
- 实现行为不受装饰栈顺序影响的装饰比较困难。
- 各层的初始化配置代码看上去可能会很
与其他模式的关系
代理模式
两者代码结构类似,但应用场景不同。装饰者模式是对原有功能增强,例如原功能是读取字符串,增强后可缓存的读取字符串。而代理模式增强的是和原功能无关的功能,例如对API接口增强,可记录接口调用时间,参数等。
其他示例
java.util.Collections#unmodifiableList
也使用了装饰器模式
public static <T> List<T> unmodifiableList(List<? extends T> list) {
return (list instanceof RandomAccess ?
new UnmodifiableRandomAccessList<>(list) :
new UnmodifiableList<>(list));
}
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);
}
};
}
- 在set、add、remove等修改方法中,以及迭代器里的修改方法中,直接抛出异常
Guava里的ForwardingCollection的作用和FileInputStream类似