在开始本文之前,我们先来看下生活中的一些场景,比如有些插头需要三口插座转两口插座。
又如美国的电压是110v,而中国的电压是220v。如果要在中国使用美国的电器,需要有一个将电压从220v转化成110v的变压器才可以适配。这样的场景就是今天要讲的适配器(Adapter)模式所做的事。
一、适配器模式的基本介绍
1.1 意图
适配器模式是一种类对象结构性模式,其意图是将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能再一起工作的那些类可以一起工作。
1.2 结构
适配器模式包括2种形式,
1、类适配
2、对象适配
主要包含如下几个部分:
定义Client使用的与特定领域相关的接口。
定义一个已经存在的接口,这个接口需要适配。
对Adaptee的接口和与Target接口进行适配。
二、类适配示例
类适配采用继承的方式实现。
package com.wangmengjun.tutorial.designpattern.adapter;
public class OldFunction {
public void handleRequest() {
System.out.println("OldFunction - handle request~~");
}
}
package com.wangmengjun.tutorial.designpattern.adapter;
public interface Target {
void request();
}
package com.wangmengjun.tutorial.designpattern.adapter;
public class ClassAdapter extends OldFunction implements Target {
public void request() {
/**
* 直接调用OldFunction的handleRequest方法即可
*/
super.handleRequest();
}
}
测试一下
package com.wangmengjun.tutorial.designpattern.adapter;
public class ClassAdapterMain {
public static void main(String[] args) {
Target target = new ClassAdapter();
//OldFunction - handle request~~
target.request();
}
}
输出
OldFunction - handle request~~
那么问题来了 - 如果适配器已经有继承,如何使用原来的功能呢?答案是可以使用对象适配来完成。
三、对象适配示例
对象适配采用的是委派的方式实现。
package com.wangmengjun.tutorial.designpattern.adapter;
public class OldFunction {
public void handleRequest() {
System.out.println("OldFunction - handle request~~");
}
}
package com.wangmengjun.tutorial.designpattern.adapter;
public interface Target {
void request();
}
package com.wangmengjun.tutorial.designpattern.adapter;
public class ObjectAdapter implements Target {
private OldFunction oldFunction;
public ObjectAdapter(OldFunction oldFunction) {
this.oldFunction = oldFunction;
}
public void request() {
/**
* 委派调用OldFunction的handleRequest方法
*/
oldFunction.handleRequest();
}
}
测试一下
package com.wangmengjun.tutorial.designpattern.adapter;
public class ObjectAdapterMain {
public static void main(String[] args) {
OldFunction adaptee = new OldFunction();
Target target = new ObjectAdapter(adaptee);
//OldFunction - handle request~~
target.request();
}
}
输出
OldFunction - handle request~~
四、小结
4.1 类适配 vs. 对象适配
类适配器和对象适配有不同的权衡。类适配器
对象适配器则:
4.2 适合适配器使用的场景
4.3 JDK中的适配器模式例子
JDK提供了多个适配器模式的例子,如
java.util.Arrays#asList()
java.util.Collections#list()
java.util.Collections#enumeration()
java.io.InputStreamReader(InputStream)
(returns a Reader
)java.io.OutputStreamWriter(OutputStream)
(returns a Writer
)
/**
* Returns an enumeration over the specified collection. This provides
* interoperability with legacy APIs that require an enumeration
* as input.
*
* <p>The iterator returned from a call to {@link Enumeration#asIterator()}
* does not support removal of elements from the specified collection. This
* is necessary to avoid unintentionally increasing the capabilities of the
* returned enumeration.
*
* @param <T> the class of the objects in the collection
* @param c the collection for which an enumeration is to be returned.
* @return an enumeration over the specified collection.
* @see Enumeration
*/
public static <T> Enumeration<T> enumeration(final Collection<T> c) {
return new Enumeration<T>() {
private final Iterator<T> i = c.iterator();
public boolean hasMoreElements() {
return i.hasNext();
}
public T nextElement() {
return i.next();
}
};
}