适配器模式
所谓适配器模式,将一个类的接口,转换为客户所期望的另一个接口。适配器让原本接口不兼容的类可以合作无间。
一般这种模式就是在不修改现有代码的情况下,将一个接口转换为另一个接口。它主要包含两种方式:对象适配器和累适配器。二者唯一的差别就在于适配器继承了Target和Adaptee。而对象适配器利用组合的方式将请求传送给被适配者。
对象适配器:
这种就是在适配器中利用了组合来处理,将被适配器作为适配器的一个成员属性,而且适配器则就实现或者继承客户所需要的目标接口。
类适配器
使用多重继承实现
真实世界的适配器
如果你已经使用过java,可能记得早期集合(collection)类型(例如:Vector、Stack、Hashtable)都实现了一个名为elements()的方法。该方法会返回一个Enumeration(举)。这个Enumeration接口可以逐一走过此集合内的每个元素。而无需知道它们在集合内是如何被管理的。
public interface Enumeration<E> {
boolean hasMoreElements();
E nextElement();
}
新世界的迭代器
当Sun推出更新后的集合类时,开始使用了Iterator(迭代器)接口,这个接口和枚举接口很像,都可以让你遍历此集合类型内的每个元素,但不同的是,迭代器还提供了删除元素的能力。
public interface Iterator<E> {
boolean hasNext();
E next();
default void remove() {
throw new UnsupportedOperationException("remove");
}
default void forEachRemaining(Consumer<? super E> action) {
Objects.requireNonNull(action);
while (hasNext())
action.accept(next());
}
}
而现在
我们经常面对遗留代码,这些代码暴露出枚举接口,但我们又希望在新的代码中只使用迭代器。就需要构造一个适配器了。
设计适配器
我们需要一个适配器,实现了目标接口,而此目标接口是被适配者所组合的,类图是这样的:
处理remove()方法
我们知道枚举不支持删除,适配器无法实现一个又实际功能的remove()方法,最多只能抛出一个运行时异常。幸运地,迭代器接口的设计者事先料到了这样的需要,所以将remove()方法定义成会抛出UnsupportedOpeartionException。
编写一个Enumeratorlterator适配器
class Enumeratorlterator implements Iterator{
Enumeration enumeration;
public Enumeratorlterator(Enumeration enumeration){
this.enumeration=enumeration;
}
@Override
public boolean hasNext() {
return enumeration.hasMoreElements();
}
@Override
public Object next() {
return enumeration.nextElement();
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
}
外观模式
所谓外观模式,就是提供一个统一接口,用来访问子系统中的一群接口。它定义了一个高层接口,让子系统更容易使用。
外观模式并没有封装了子系统的类,外观只是提供了更简化的接口,它里面仍然包含着子系统中各个接口的对象,并且利用组合将子系统的所有接口来包含起来。它不仅提供了一个简化接口,而且依然将系统完整的功能暴露出来。
- 适配器模式将一个或者多个类接口变成客户所期望的接口,并不是转换一个接口。(双向适配器)
- 外观模式也可以只针对一个拥有复杂接口的类提供简化的接口。你可以为一个子系统实现一个以上的外观。
设计意图
- 适配器模式的意图,是改变接口以符合client的期望。
- 外观模式的意图,是提供复杂子系统的一个简化接口,让接口更简单。
- 装饰者模式的意图,是不改变接口,但加入新的行为和责任
使用要点
- 当需要使用一个现有的类,但其接口并不符合你的需要时,使用适配器。
- 当需要简化并统一一个很大的接口或者一群复杂的接口时,使用外观。