zoukankan      html  css  js  c++  java
  • 设计模式之适配器模式

    适配器模式

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

  • 相关阅读:
    suse12安装详解
    Centos7上部署openstack mitaka配置详解(将疑难点都进行划分)
    菜鸟帮你跳过openstack配置过程中的坑[文末新添加福利]
    openstack中dashboard页面RuntimeError: Unable to create a new session key. It is likely that the cache is unavailable.
    Multiple network matches found for name 'selfservice', use an ID to be more specific.报错
    查看 SELinux状态及关闭SELinux
    SELinux深入理解
    IP地址、子网掩码、网络号、主机号、网络地址、主机地址
    Oracle job procedure 存储过程定时任务
    POI文件导出至EXCEL,并弹出下载框
  • 原文地址:https://www.cnblogs.com/JIATCODE/p/13069051.html
Copyright © 2011-2022 走看看