设计模式 8 - 适配器模式与springmvc源码分析

目录

适配器模式

1.基本介绍

2.工作原理

3. 类适配器

1. 角色

2.例子演示

3. 类图

4. 代码

5. 类适配器小结

4. 对象适配器(继承改聚合)

1. 介绍

2. 类图

3. 代码(由类适配器的代码改变而得)

4. 对象适配器小结

5. 接口适配器(缺省适配器)

1. 介绍

2. 图解

3. 代码演示

6. 适配器模式在springmvc中的分析

1.类图分析

自己编写代码模拟实现过程


 

适配器模式

博主一句话总结(非准确):继承被适配的类(Voltage220V),实现适配的接口。传入了什么类型的对象就能够获取对应的适配器,也自动的去调用对应的方法,增加了灵活性,而且扩展功能时只需要增加对应的适配器模块。

1.基本介绍

  • 适配器模式(Adapter Pattern)将某个类的接口转换成客户端期望的另一个接口表示,主要目的是兼容性,让原本因接口不匹配不能工作的两个类可以协同工作,其别名为包装器(Wrapper)
  • 适配器模式属于结构型模式
  • 分为三类:类配置器模式、对象配置器模式、接口适配器模式

2.工作原理

  • 适配器模式:将一个类的接口转换为另一个接口,让原本接口不兼容的类可以兼容
  • 从用户的角度看不到被适配者,是解耦的
  • 用户调用适配器转化出来的目标接口方法,适配器再调用被适配者的相关接口方法
  • 用户收到反馈结果,感觉只是和目标接口交互

3. 类适配器

1. 角色

  • Target(目标抽象类):目标抽象类定义客户所需接口,可以是一个抽象类或接口,也可以是具体类。
  • Adapter(适配器类):适配器可以调用另一个接口,作为一个转换器,对Adaptee和Target进行适配,适配器类是适配器模式的核心,在对象适配器中,它通过继承Target并关联一个Adaptee对象使二者产生联系。
  • Adaptee(适配者类):适配者即被适配的角色,它定义了一个已经存在的接口,这个接口需要适配,适配者类一般是一个具体类,包含了客户希望使用的业务方法,在某些情况下可能没有适配者类的源代码。

2.例子演示

我们国家的民用电都是 220V,日本是 110V,而我们的手机充电一般需要 5V,这时候要充电,就需要一个电压适配器,将 220V 或者 100V 的输入电压变换为 5V 输出,继承被适配的类(Voltage220V),实现适配的接口(Voltage5V)。

3. 类图

4. 代码

定义一个被适配的类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,同时实现用户适合的接口,在这之中进行转换,实现调用Voltage220V的方法,然后输出Voltage5V需要的方法

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");
	}
}

最后测试一下,会发现输出的是5v电压。

public class client {
	public static void main(String[] args) {
		Phone phone = new Phone();
        //使用VoltageAdapter充电器对手机进行充电
		phone.charging(new VoltageAdapter());
	}
}

5. 类适配器小结

  • java是单继承机制,所以类适配器需要继承src类这一点是一个缺点,而且这要求dst必须是一个接口,有一定局限性
  • src类的方法都在Adapter中暴露出来
  • 优点:Adapter继承了src类,所以它可以根据需求重写src类的方法,使得Adapter的灵活性增加了

4. 对象适配器(继承改聚合)

1. 介绍

  1. 与类适配器的思想相同,不同的是它对Adapter类做修改,不是继承src类,而是聚合src对象,持有他的实例,以解决兼容性的问题
  2. 根据"合成复用原则",在系统中尽量使用关联关系来替代继承关系
  3. 适配器模式中比较常用的一种

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. 对象适配器小结

  1. 使用聚合代替了继承,解决了类适配器必须继承src的局限性问题,也不再要求dst必须是接口
  2. 使得更加灵活

5. 接口适配器(缺省适配器)

1. 介绍

  1. 当不需要实现接口中的全部方法时,只要定义一个抽象类继承接口,给每一个方法默认实现(空方法),之后该抽象类的子类只需要有选择性的重写某些方法来实现需求
  2. 适用于一个接口不想使用其所有的方法

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()方法

自己编写代码模拟实现过程

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();
	}
}

2. 定义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....");
	}
}

3. 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......
	}
}

7. 小结

可以发现在doDispatch中我们获取适配器的时候传入了什么类型的Controller就能够获取对应的适配器,也自动的去调用对应的Controller执行Handler,在这一步完全可以适应传入的Controller,不会因为传入不同的Controller代码失去作用,增加了灵活性,而且扩展功能时只需要增加对应的适配器模块和Controller模块,配置在SpringMVC中,就一样可以被使用,代码不用进行改动,这就是适配器模式的关键作用。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值