适配器模式
1.基本介绍
- 适配器模式(Adapter Pattern)将某个类的接口转换成客户端期望的另一个接口表示,主要目的是兼容性,让原本因接口不匹配不能工作的两个类可以协同工作,其别名为包装器(Wrapper)
- 适配器模式属于结构型模式
- 分为三类:类配置器模式、对象配置器模式、接口适配器模式
2.工作原理
- 适配器模式:将一个类的接口转换为另一个接口,让原本接口不兼容的类可以兼容
- 从用户的角度看不到被适配者,是解耦的
- 用户调用适配器转化出来的目标接口方法,适配器再调用被适配者的相关接口方法
- 用户收到反馈结果,感觉只是和目标接口交互
3.类适配器
1.介绍
-
Adapter类,通过继承src类,实现dst类接口,完成src->dst的适配
-
作用:将原本不兼容的接口融合在一起工作
2. 工作原理图
3.代码实现示例
定义Voltage220V
//被适配对象:模拟220V的插座
public class Voltage220V {
private int src = 220;
//输出220V电压
public int output220V() {
System.out.println("电压="+src+"伏");
return src;
}
}
定义一个适合用户使用的接口
public interface IVoltage5V {
public int output5V();
}
由一个适配器来继承被适配的对象Voltage220V,同时实现用户适合的接口,在这之中进行转换
public class VoltageAdapter extends Voltage220V implements IVoltage5V {
@Override
public int output5V() {
// TODO Auto-generated method stub
int src = output220V();
//模拟src->dst的适配
int dst =src/44;
return dst;
}
}
定义一个phone,这里充当适配器模式中的使用者,因此在这里聚合接口IVoltage5V,遵守
依赖倒置原则
public class Phone {
//定义手机的充电功能,聚合一个充电器接口
public void charging(IVoltage5V iVoltage5V) {
int src = iVoltage5V.output5V();
System.out.println("输出"+src+"V");
}
}
最后由用户来决定用哪个适配器来对手机进行充电
public class client {
public static void main(String[] args) {
Phone phone = new Phone();
//使用VoltageAdapter充电器对手机进行充电
phone.charging(new VoltageAdapter());
}
}
以上为对工作原理图的实现,参考该例子的实现思想和结构
4.类配置器小结
- java是单继承机制,所以类适配器需要继承src类这一点是一个缺点,而且这要求dst必须是一个接口,有一定局限性
- src类的方法都在Adapter中暴露出来
- 优点:Adapter继承了src类,所以它可以根据需求重写src类的方法,使得Adapter的灵活性增加了
4.对象适配器
1.介绍
- 与类适配器的思想相同,不同的是它对Adapter类做修改,不是继承src类,而是聚合src对象,持有他的实例,以解决兼容性的问题
- 根据"合成复用原则",在系统中尽量使用关联关系来替代继承关系
- 适配器模式中比较常用的一种
2.工作原理图
3.代码示例
VoltageAdapter不再继承Voltage220V,而是直接聚合
public class VoltageAdapter implements IVoltage5V {
//聚合Voltage220V对象
private Voltage220V voltage;
public VoltageAdapter(Voltage220V voltage) {
// TODO Auto-generated constructor stub
this.voltage = voltage;
}
@Override
public int output5V() {
// TODO Auto-generated method stub
int dst=0;
if(voltage!=null){
int src = voltage.output220V();
//模拟src->dst
dst =src/44;
}
return dst;
}
}
使用上
public class client {
public static void main(String[] args) {
Phone phone = new Phone();
//构造时需要传入被适配对象
phone.charging(new VoltageAdapter(new Voltage220V()));
}
}
4.对象适配器小结
- 使用聚合代替了继承,解决了类适配器必须继承src的局限性问题,也不再要求dst必须是接口
- 使得更加灵活
5.接口适配器(缺省适配器)
1.定义
- 当不需要实现接口中的全部方法时,只要定义一个抽象类继承接口,给每一个方法默认实现(空方法),之后该抽象类的子类只需要有选择性的重写某些方法来实现需求
- 适用于一个接口不想使用其所有的方法
2.工作图解
3.代码示例
定义接口
public interface Interface2 {
public void m1();
public void m2();
public void m3();
}
默认实现接口中的方法
public class AbsA implements Interface2{
@Override
public void m1() {
// TODO Auto-generated method stub
}
@Override
public void m2() {
// TODO Auto-generated method stub
}
@Override
public void m3() {
// TODO Auto-generated method stub
}
}
使用适配器时继承AbsA或者在创建AbsA的时候可以选择性的重写某些方法
//创建对象的时候重写
AbsA a = new AbsA() {
@Override
public void m2() {
// TODO Auto-generated method stub
//进行方法实现
super.m2();
}
};
6.适配器模式在springMVC框架中的分析
模拟适配器调用流程
1.类图分析如下
DispatchServlet中首先得到一个Controller类型,我们通过该Controller类型来获取HandlerAdapter的对应适配器类型,得到这个适配器之后我们就可以调用对应的Controller的doHandler()方法
2.自己编写代码模拟实现
- 定义HandlerAdapter
//定义一个Adapter接口
public interface HandlerAdapter {
//判断是否为对应的Controller类型
public boolean supports(Object handler);
//执行对应的控制器方法
public void handler(Object handler);
}
//实现多种适配器类
class SimpleHandlerAdapter implements HandlerAdapter{
@Override
public boolean supports(Object handler) {
return (handler instanceof SimpleController);
}
@Override
public void handler(Object handler) {
((SimpleController)handler).doSimpleHandler();
}
}
class HttpHandlerAdapter implements HandlerAdapter{
//判断是否为对应的Controller类型
@Override
public boolean supports(Object handler) {
return (handler instanceof HttpController);
}
@Override
public void handler(Object handler) {
//执行对应的控制器方法
((HttpController)handler).doHttpHandler();
}
}
class AnnotationHandlerAdapter implements HandlerAdapter{
//判断是否为对应的Controller类型
@Override
public boolean supports(Object handler) {
return (handler instanceof AnnotationController);
}
@Override
public void handler(Object handler) {
//执行对应的控制器方法
((AnnotationController)handler).doAnnotationHandler();
}
}
- 定义Controller
//模拟Controller的实现和各自的doHandler()方法
public interface Controller {
}
class HttpController implements Controller{
public void doHttpHandler() {
System.out.println("HttpHandler....");
}
}
class AnnotationController implements Controller{
public void doAnnotationHandler() {
System.out.println("AnnotationHandler....");
}
}
class SimpleController implements Controller{
public void doSimpleHandler() {
System.out.println("SimpleHandler....");
}
}
- DispatchServlet类,这里先用list来模拟SpringMVC中配置的所有适配器,doDispatch中模拟SpringMVC从request中获取handler对象
public class DispatchServlet {
//模拟配置适配器
public static List<HandlerAdapter> handlerAdapters= new ArrayList<>();
static {
handlerAdapters.add(new AnnotationHandlerAdapter());
handlerAdapters.add(new HttpHandlerAdapter());
handlerAdapters.add(new SimpleHandlerAdapter());
}
public void doDispatch() {
//模拟SpringMVC从request中获取handler的对象
//适配器在这里可以获取匹配的Controller
AnnotationController controller = new AnnotationController();
// SimpleController controller = new SimpleController();
// HttpController controller = new HttpController();
//通过controller获取适配器
HandlerAdapter adapter = getHandler(controller);
//通过适配器执行对应的Controller方法
adapter.handler(controller);
}
private HandlerAdapter getHandler(Controller controller) {
// 模拟源码:通过遍历的方式来匹配适配与controller类型
for(HandlerAdapter handler : this.handlerAdapters) {
if(handler.supports(controller)) {
return handler;
}
}
return null;
}
public static void main(String[] args) {
//模拟调用
new DispatchServlet().doDispatch(); //输出AnnotationHandler......
}
}
小结
可以发现在doDispatch中我们获取适配器的时候传入了什么类型的Controller就能够获取对应的适配器,也自动的去调用对应的Controller执行Handler,在这一步完全可以适应传入的Controller,不会因为传入不同的Controller代码失去作用,增加了灵活性,而且**扩展功能时只需要增加对应的适配器模块和Controller模块,配置在SpringMVC中,就一样可以被使用,代码不用进行改动,这就是适配器模式的关键作用