介绍
适配器模式是两个不兼容接口间的桥梁,属于结构型模式。适配器模式分为三类,类适配器模式,对象适配器模式,接口适配器模式。我们生活中有很多适配器模式的例子,例如我们给手机充电,家庭电压是220V直流,手机的电压是5V交流,但是我们依然可以直接给手机充电,就是因为充电器充当了适配器的角色。
1.类适配器模式
演示
例子:把220V直流适配成5V交流。
类图:
Voltage220V类
package com.jc.adapter.classadapter;
/**
* @program: 设计模式
* @description:被适配者
* @author: Mr.Wang
* @create: 2021-06-16 20:03
**/
public class Voltage220V {
public int output220V() {
int src = 220;
return src;
}
}
Voltage5V接口
package com.jc.adapter.classadapter;
/**
* 目标接口
*/
public interface Voltage5V {
int output5V();
}
VoltageApdapter类
package com.jc.adapter.classadapter;/**
* @program: 设计模式
*
* @description: 适配器
*
* @author: Mr.Wang
*
* @create: 2021-06-16 20:05
**/
public class VoltageAdapter extends Voltage220V implements Voltage5V {
@Override
public int output5V() {
int src = output220V();
src = src / 44;
System.out.println("220V已经适配成5V啦!可以充电啦!");
return src;
}
}
Phone类
package com.jc.adapter.classadapter;/**
* @program: 设计模式
*
* @description:
*
* @author: Mr.Wang
*
* @create: 2021-06-16 20:06
**/
public class Phone {
//充电
public void charging(Voltage5V voltage5V){
if (voltage5V.output5V() == 5){
System.out.println("电压为5V~可以充电");
}else if(voltage5V.output5V() > 5){
System.out.println("电压大于5V~不可以充电!");
}
}
}
Client
package com.jc.adapter.classadapter;/**
* @program: 设计模式
*
* @description:
*
* @author: Mr.Wang
*
* @create: 2021-06-16 20:08
**/
public class Client {
public static void main(String[] args) {
System.out.println("========类适配器模式=========");
Phone phone = new Phone();
phone.charging(new VoltageAdapter());
// ========类适配器模式=========
// 220V已经适配成5V啦!可以充电啦!
// 电压为5V~可以充电
}
}
java是单继承模式,这里适配器继承了220V直流,实现了5V交流接口,接口可以是很多个,但是只能继承一个。
我们继承220V直流的目的时什么?
就是想用他里边的output220V这个方法,然后通过一顿操作将他改成5V直流。根据合成符用原则,如果B类仅仅想使用A类中的方法,我们尽量使用组合和聚合的方式,而不是通过继承。继承带来的后果就是:侵入性,不够灵活,高耦合。
所以我们能用组合和聚合就不要使用继承。
所以我们引出对象适配器模式
2.对象适配器模式
我们只需要把220V直流那个类聚合到适配器类里边就ok了。
类图
新的适配器类
package com.jc.adapter.objectadapter;
/**
* @program: 设计模式
*
* @description: 适配器
*
* @author: Mr.Wang
*
* @create: 2021-06-16 20:05
**/
public class VoltageAdapter implements Voltage5V {
//聚合进来
Voltage220V voltage220V;
public VoltageAdapter(Voltage220V voltage220V) {
this.voltage220V = voltage220V;
}
@Override
public int output5V() {
int src = voltage220V.output220V();
src = src / 44;
System.out.println("220V已经适配成5V啦!可以充电啦!");
return src;
}
}
Client
package com.jc.adapter.objectadapter;
import jdk.internal.dynalink.beans.StaticClass;
import java.util.*;
/**
* @program: 设计模式
*
* @description:
*
* @author: Mr.Wang
*
* @create: 2021-06-16 20:08
**/
public class Client {
public static void main(String[] args) {
System.out.println("========对象适配器模式=========");
Phone phone = new Phone();
phone.charging(new VoltageAdapter(new Voltage220V()));
// ========对象适配器模式=========
// 220V已经适配成5V啦!可以充电啦!
// 电压为5V~可以充电
}
}
依然可以实现相同效果,相比于类适配器更加灵活,耦合性低。
3.接口适配器模式
1.接口适配器模式又被称为 缺省适配器模式;
2.当不需要全部实现接口提供的方法时,可先设计一个抽象类实现接口,并为该接口中每个方法提供一个默认实现(空方法),那么该抽象类的子类可有选择地覆盖父类的某些方法来实现需求。
类图
Interface4
package com.jc.adapter.interfaceadapter;
public interface Interface4 {
void m1();
void m2();
void m3();
void m4();
void m5();
}
AbstractAdapter
package com.jc.adapter.interfaceadapter;/**
* @program: 设计模式
*
* @description:
*
* @author: Mr.Wang
*
* @create: 2021-06-17 21:54
**/
public abstract class AbstractAdapter implements Interface4 {
@Override
public void m1() {
}
@Override
public void m2() {
}
@Override
public void m3() {
}
@Override
public void m4() {
}
@Override
public void m5() {
}
}
ConcreteAdapter1
package com.jc.adapter.interfaceadapter;/**
* @program: 设计模式
*
* @description:
*
* @author: Mr.Wang
*
* @create: 2021-06-17 21:59
**/
public class ConcreteAdapter1 extends AbstractAdapter {
@Override
public void m1() {
System.out.println("第一个适配器:我要用m1 所以实现了m1");
}
public ConcreteAdapter1(){
System.out.println("=====我是第一个适配器====我只实现了m1,m3");
}
@Override
public void m3() {
System.out.println("第一个适配器:我要用m3 所以实现了m3");
}
}
ConcreteAdapter2
package com.jc.adapter.interfaceadapter;/**
* @program: 设计模式
*
* @description:
*
* @author: Mr.Wang
*
* @create: 2021-06-17 21:59
**/
public class ConcreteAdapter2 extends AbstractAdapter {
public ConcreteAdapter2(){
System.out.println("=====我是第二个适配器====我只实现了m2,m4");
}
@Override
public void m2() {
System.out.println("第二个适配器:我要用m2 所以实现了m2");
}
@Override
public void m4() {
System.out.println("第二个适配器:我要用m4 所以实现了m4");
}
}
Client
package com.jc.adapter.interfaceadapter;/**
* @program: 设计模式
*
* @description:
*
* @author: Mr.Wang
*
* @create: 2021-06-17 21:54
**/
public class Client {
public static void main(String[] args) {
//第一个适配器
AbstractAdapter adapter1 = new ConcreteAdapter1();
adapter1.m1();
adapter1.m3();
//第二个适配器
AbstractAdapter adapter2 = new ConcreteAdapter2();
adapter2.m2();
adapter2.m4();
// =====我是第一个适配器====我只实现了m1,m3
// 第一个适配器:我要用m1 所以实现了m1
// 第一个适配器:我要用m3 所以实现了m3
// =====我是第二个适配器====我只实现了m2,m4
// 第二个适配器:我要用m2 所以实现了m2
// 第二个适配器:我要用m4 所以实现了m4
}
}
通过打印结果我们实现了自己想要的适配器,并实现了自己的操作。
在源码中应用
1.HttpServlet继承GenericServlet,GenericServlet空实现于javax.servlet.Servlet
2.在springMVC框架中的应用
HandlerAdapter
public interface HandlerAdapter {
boolean supports(Object var1);
@Nullable
ModelAndView handle(HttpServletRequest var1, HttpServletResponse var2, Object var3) throws Exception;
long getLastModified(HttpServletRequest var1, Object var2);
}
HttpRequestHandlerAdapter (其中一个具体的适配器)
public class HttpRequestHandlerAdapter implements HandlerAdapter {
public HttpRequestHandlerAdapter() {
}
public boolean supports(Object handler) {
return handler instanceof HttpRequestHandler;
}
@Nullable
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
((HttpRequestHandler)handler).handleRequest(request, response);
return null;
}
public long getLastModified(HttpServletRequest request, Object handler) {
return handler instanceof LastModified ? ((LastModified)handler).getLastModified(request) : -1L;
}
}
如何应用的?
DispatchServlet中的doDispatch方法
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
//根据HandlerMapping获取对应的Handler(Controller)
mappedHandler = this.getHandler(processedRequest);
//没有根据映射拿到Handler的话报错。
if (mappedHandler == null) {
this.noHandlerFound(processedRequest, response);
return;
}
//从handlerAdapters选择一个支持具体的Hander的适配器
HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
//根据适配器进行处理,然后返回结果.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
}
getHandlerAdapter方法
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
if (this.handlerAdapters != null) {
//遍历handlerAdapters选择合适的HandlerAdapter
for (HandlerAdapter adapter : this.handlerAdapters) {
if (adapter.supports(handler)) {
return adapter;
}
}
}
throw new ServletException("No adapter for handler [" + handler + "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}
总结
好:
1、将目标类和适配者类解耦,(譬如上边的,将DispatchServlet和具体的适配器解耦)
2、增加了类的透明性和复用性,将具体的实现封装在适配者类中,对于客户端类来说是透明的,而且提高了适配者的复用性
3、灵活性和扩展性都非常好,符合开闭原则
不好:
适配器编写过程需要结合业务场景全面考虑,可能会增加系统的复杂
降低代码可读性,过多使用适配器会使系统代码变得很难懂。