• 设计模式之适配器模式


    适配器模式

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

  • 相关阅读:
    【转】Linux目录结构FHS
    单链表是否有环并如何找到环入口
    【转】linux dd 的简单应用
    DataSet、ExecuteScalar、ExecuteReader
    解决Excel只验证前8行字符串的长度
    SQL Server UPSERT equivalent
    用通配符替换字符串
    从内存中查询表字段定义的长度大小
    C#判断一个字符串是否为整数
    page life cycle of master page with content page
  • 原文地址:https://www.cnblogs.com/JIATCODE/p/13069051.html
Copyright © 2020-2023  润新知