适配器模式(Adapter Pattern)将某个类的接口转换成客户端期望的另一个接口表示,主的目的是兼容性,让原本因接口不匹配不能一起工作的两个类可以协同工作,其别名为包装器(Wrapper)。
适配器模式属于结构型模式。
适配器模式主要分为三类:类适配器模式、对象适配器模式、接口适配器模式。
工作原理:
(1)适配器模式:将一个类的接口转换成另一种接口,让原本接口不兼容的类可以兼容。
(2)用户调用适配器转化出来的目标接口方法,然后适配器再调用被适配者的相关接口方法。
(3)从用户的角度看不到被适配者,是解耦的。用户收到反馈结果,感觉只是和目标接口交互。
基本介绍:Adapter类,通过继承src类和实现dst接口,完成src到dst的适配。
以生活中充电器的例子来讲解适配器,充电器本身相当于Adapter,220V交流电相当于src(被适配者),5V直流电相当于dst(目标最终需要的输出)。
使用类适配器模式实现应用实例。
类图:
代码实现:
package com.etc.design.dapter.classadapter;
// 被适配的类
public class Voltage220V {
//输出220V的电压
public int output220V() {
int src = 220;
System.out.println("电压=" + src + "伏");
return src;
}
}
package com.etc.design.dapter.classadapter;
// 适配接口
public interface IVoltage5V {
public int output5V();
}
package com.etc.design.dapter.classadapter;
// 适配器类
public class VoltageAdapter extends Voltage220V implements IVoltage5V {
@Override
public int output5V() {
//获取到220V电压
int srcV = output220V();
//转成 5v
int dstV = srcV / 44 ;
return dstV;
}
}
package com.etc.design.dapter.classadapter;
public class Phone {
// 充电
public void charging(IVoltage5V iVoltage5V) {
if(iVoltage5V.output5V() == 5) {
System.out.println("电压为5V, 可以充电。");
} else if (iVoltage5V.output5V() > 5) {
System.out.println("电压大于5V, 不能充电。");
}
}
}
package com.etc.design.dapter.classadapter;
public class Client {
public static void main(String[] args) {
System.out.println("----类适配器模式----");
Phone phone = new Phone();
phone.charging(new VoltageAdapter());
}
}
(1)由于Java是单继承机制,所以类适配器需要继承src类这一点算是一个缺点, 因为这要求dst必须是接口,有一定局限性。
(2)src类的方法在Adapter中都会暴露出来,也增加了使用的成本。
(3)由于Adapter继承了src类,所以它可以根据需求重写src类的方法,使得Adapter的灵活性增强了。
(1)基本思路和类的适配器模式相同,只是将Adapter类稍作修改,不是继承src类,而是持有src类的实例对象,以解决兼容性的问题。 即:持有src类的实例对象,实现dst接口,完成src到dst的适配。
(2)根据”合成复用原则“,在系统中尽量使用关联关系(聚合)来替代继承关系。
(3)对象适配器模式是适配器模式常用的一种。
以生活中充电器的例子来讲解适配器,充电器本身相当于Adapter,220V交流电相当于src(被适配者),5V直流电相当于dst(目标最终需要的输出)。
使用对象适配器模式实现应用实例:
类图:
实现代码:
package com.etc.design.dapter.objectadapter;
// 适配接口
public interface IVoltage5V {
public int output5V();
}
package com.etc.design.dapter.objectadapter;
// 被适配的类
public class Voltage220V {
//输出220V的电压
public int output220V() {
int src = 220;
System.out.println("电压=" + src + "伏");
return src;
}
}
package com.etc.design.dapter.objectadapter;
public class Phone {
// 充电
public void charging(IVoltage5V iVoltage5V) {
if(iVoltage5V.output5V() == 5) {
System.out.println("电压为5V, 可以充电。");
} else if (iVoltage5V.output5V() > 5) {
System.out.println("电压大于5V, 不能充电。");
}
}
}
package com.etc.design.dapter.objectadapter;
// 适配器类
public class VoltageAdapter implements IVoltage5V {
// 关联关系-聚合关系
private Voltage220V voltage220V;
// 通过构造器,传入一个Voltage220V实例
public VoltageAdapter(Voltage220V voltage220v) {
this.voltage220V = voltage220v;
}
@Override
public int output5V() {
int dst = 0;
if(null != voltage220V) {
// 获取220V电压
int src = voltage220V.output220V();
System.out.println("使用对象适配器,进行适配。");
dst = src / 44;
System.out.println("适配完成,输出的电压为=" + dst);
}
return dst;
}
}
package com.etc.design.dapter.objectadapter;
public class Client {
public static void main(String[] args) {
System.out.println("----对象适配器模式----");
Phone phone = new Phone();
phone.charging(new VoltageAdapter(new Voltage220V()));
}
}
(1)对象适配器和类适配器其实算是同一种思想,只不过实现方式不同。根据合成复用原则,使用组合关系代替继承关系, 所以它解决了类适配器必须继承src的局限性问题,也不再要求dst必须是接口。
(2)使用成本更低、更灵活。
(1)接口适配器模式也称为缺省适配器模式(Default Adapter Pattern)。
(2)核心思路:当不需要全部实现接口提供的方法时,可先设计一个抽象类实现接口,并为该接口中每个方法提供一个默认实现(空方法),那么该抽象类的子类可有选择地覆盖父类的某些方法来实现需求。
(3)适用于不想使用接口中所有的方法的情况。
类图:
实现代码:
package com.etc.design.dapter.interfaceadapter;
public interface InterfaceDemo {
public void method1();
public void method2();
public void method3();
public void method4();
}
package com.etc.design.dapter.interfaceadapter;
// 在AbstractAdapterDemo将InterfaceDemo的方法进行默认实现(空方法)
public abstract class AbstractAdapterDemo implements InterfaceDemo{
// method1方法默认实现(空方法)
public void method1() {}
// method2方法默认实现(空方法)
public void method2() {}
// method3方法默认实现(空方法)
public void method3() {}
// method4方法默认实现(空方法)
public void method4() {}
}
package com.etc.design.dapter.interfaceadapter;
public class Client {
public static void main(String[] args) {
AbstractAdapterDemo abstractAdapterDemo = new AbstractAdapterDemo() {
//只需要去重写需要到使用的接口方法
@Override
public void method1() {
System.out.println("使用了method1方法");
}
};
abstractAdapterDemo.method1();
}
}
(1)SpringMVC中的HandlerAdapter使用了适配器模式。
(2)使用HandlerAdapter原因分析:
if else
语句来进行判断是哪一种子类,然后再执行。如果后面需要扩展Controller,就要修改原来的代码,这样违背了OCP原则。(3)使用适配器设计模式分析:
具体说明:DispatcherServlet方法的doDispatch方法中传入request,将request通过HandlerMapping映射到对应的Controller,通过controller获取相对应的适配器,通过调用该适配器的handle方法(该适配器的handle方法会调用Controller的handle方法)并返回ModelAndVew。
@SuppressWarnings("serial")
public class DispatcherServlet extends FrameworkServlet {
...
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
ModelAndView mv = null;
// Handler可看成一个controller
HandlerExecutionChain mappedHandler = null;
......
processedRequest = checkMultipart(request);
......
// 1、通过HandlerMapping来映射Controller
mappedHandler = getHandler(processedRequest);
......
// 2、通过controller获取相对应的适配器
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
......
// 3、通过适配器调用controller的handle方法并返回ModelAndVew
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
......
}
......
// 通过controller获取相对应的适配器
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
for (HandlerAdapter ha : this.handlerAdapters) {
if (logger.isTraceEnabled()) {
logger.trace("Testing handler adapter [" + ha + "]");
}
if (ha.supports(handler)) {
return ha;
}
}
throw new ServletException("No adapter for handler [" + handler +
"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}
......
}
// Spring创建了一个适配器接口(HandlerAdapter),适配器接口有多个适配器实现类
public interface HandlerAdapter {
boolean supports(Object handler);
ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
long getLastModified(HttpServletRequest request, Object handler);
}
// 例如HttpRequestHandlerAdapter适配器实现类(HandlerAdapter的实现子类之一)
public class HttpRequestHandlerAdapter implements HandlerAdapter {
@Override
public boolean supports(Object handler) {
return (handler instanceof HttpRequestHandler);
}
// handle方法调用的是对应controller的handle方法
@Override
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
((HttpRequestHandler) handler).handleRequest(request, response);
return null;
}
@Override
public long getLastModified(HttpServletRequest request, Object handler) {
if (handler instanceof LastModified) {
return ((LastModified) handler).getLastModified(request);
}
return -1L;
}
}
(4)简写模拟SpringMVC通过适配器设计模式获取到对应的Controller的源码。
类图:
实现代码:
package com.etc.design.dapter.springmvc;
// Controller有多个实现子类
public interface Controller {
}
class HttpController implements Controller {
public void doHttpHandler() {
System.out.println("http...");
}
}
class SimpleController implements Controller {
public void doSimplerHandler() {
System.out.println("simple...");
}
}
class AnnotationController implements Controller {
public void doAnnotationHandler() {
System.out.println("annotation...");
}
}
package com.etc.design.dapter.springmvc;
// 定义一个Adapter适配器接口
public interface HandlerAdapter {
public boolean supports(Object handler);
public void handle(Object handler);
}
// 多种Adapter适配器类
class SimpleHandlerAdapter implements HandlerAdapter {
public void handle(Object handler) {
((SimpleController) handler).doSimplerHandler();
}
public boolean supports(Object handler) {
return (handler instanceof SimpleController);
}
}
class HttpHandlerAdapter implements HandlerAdapter {
public void handle(Object handler) {
((HttpController) handler).doHttpHandler();
}
public boolean supports(Object handler) {
return (handler instanceof HttpController);
}
}
class AnnotationHandlerAdapter implements HandlerAdapter {
public void handle(Object handler) {
((AnnotationController) handler).doAnnotationHandler();
}
public boolean supports(Object handler) {
return (handler instanceof AnnotationController);
}
}
package com.etc.design.dapter.springmvc;
import java.util.ArrayList;
import java.util.List;
public class DispatchServlet {
public static List<HandlerAdapter> handlerAdapters = new ArrayList<HandlerAdapter>();
public DispatchServlet() {
handlerAdapters.add(new AnnotationHandlerAdapter());
handlerAdapters.add(new HttpHandlerAdapter());
handlerAdapters.add(new SimpleHandlerAdapter());
}
public void doDispatch() {
// 此处模拟SpringMVC从request取handler(可以看成controller)的对象
HttpController controller = new HttpController();
// AnnotationController controller = new AnnotationController();
// SimpleController controller = new SimpleController();
// 通过controller得到对应适配器
HandlerAdapter adapter = getHandler(controller);
// 通过适配器执行对应的controller对应方法
adapter.handle(controller);
}
public HandlerAdapter getHandler(Controller controller) {
//遍历handlerAdapters集合, 根据得到的controller, 返回对应适配器
for (HandlerAdapter adapter : this.handlerAdapters) {
if (adapter.supports(controller)) {
return adapter;
}
}
return null;
}
public static void main(String[] args) {
// 测试
new DispatchServlet().doDispatch();
}
}
(1)适配器模式的三种命名方式,是根据src是以怎样的形式给到Adapter(在Adapter里的形式)来命名的。
(2)Adapter模式最大的作用是将原本不兼容的接口融合在一起工作。
(3)在实际开发中,适配器模式实现起来不拘泥于三种经典形式。