设计模式之适配器模式

适配器模式

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.自己编写代码模拟实现

  1. 定义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();
	}
}
  1. 定义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....");
	}
}
  1. 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中,就一样可以被使用,代码不用进行改动,这就是适配器模式的关键作用

原文地址:https://www.cnblogs.com/JIATCODE/p/13069051.html