文章目录
1. 项目需求分析
1.1 显示生活中的例子
假如去泰国旅游,泰国的插座都是两孔的(欧标),而我们国家的插座但是三孔的,于是可以买个多功能转换插头(适配器),这样就可以使用了。
2. 什么是适配器模式?
- 适配器模式(Adapter Pattern)将某个类的接口转换成客户端期望的另一个接口表示,主要目的是兼容性,让原本因接口不匹配而不能在一起工作的两个类可以协同工作。其别名为包装器(Wrapper)
- 适配器模式属于结构型模式。
- 主要分为3类:适配器模式、对象适配器模式、接口适配器模式。
3. 适配器模式的工作原理
- 适配器模式:将一个类接口转换成另一种接口,让原本接口不兼容的类可以兼容。
- 从用户的角度看不到被适配者,是解耦的。
- 用户调用适配器转化出来的目标接口方法,适配器再调用被适配者的相关接口方法。
- 用户收到反馈结果,感觉只是和目标接口交互,如图
4. 类适配器
4.1 类适配器基本介绍
Adapter类,通过继承src类,实现dst类接口,完成src->dst的适配。
4.2 类适配器模式应用实例
- 以生活中充电器的例子来讲解适配器,充电器本身相当于Adapter,220V交流电相当于src(即被适配者),我们的dst(即 目标)是5V直流电。
4.2 用类图来描述
4.3 上代码
4.3.1 被适配器类
/**
* @author LongXi
* @create 2021-08-11 21:11
*/
//被适配器类
public class Voltage220V {
public int output220V(){
int src = 220;
System.out.println("电压="+ src + "伏");
return src;
}
}
4.3.2 适配接口
/**
* @author LongXi
* @create 2021-08-11 21:13
*/
//适配接口
public interface IVoltage5V {
public int output5V();
}
4.3.3 适配器类
/**
* @author LongXi
* @create 2021-08-11 21:14
*/
//适配器类
public class VoltageAdapter extends Voltage220V implements IVoltage5V {
@Override
public int output5V() {
//获取220V电压
int srcV = output220V();
//转成5V
int dstV = srcV / 44;
return dstV;
}
}
4.3.4 手机类,使用适配器
/**
* @author LongXi
* @create 2021-08-11 21:17
*/
public class Phone {
//充电
public void charging(IVoltage5V iVoltage5V){
if (iVoltage5V.output5V() == 5){
System.out.println("电压为5V,可以充电~~");
} else if (iVoltage5V.output5V() > 5){
System.out.println("电压大于5V,不能充电~~");
}
}
}
4.3.5 测试类
/**
* @author LongXi
* @create 2021-08-11 21:21
*/
public class Client {
public static void main(String[] args) {
System.out.println("类适配器模式");
Phone phone = new Phone();
phone.charging(new VoltageAdapter());
}
}
4.3.6 运行结果
电压=220伏
电压为5V,可以充电~~
4.4 类适配器模式注意事项和细节
4.4.1 缺点
- Java是单继承机制,所以类适配器需要继承src类,至一点算是一个缺点,因为这要求dst必须是接口,有一定局限性。
- src类方法在Adapter中都会暴露出来,也增加了使用的成本(output220V)。
4.4.2 优点
由于其继承了src类,所以它可以根据需求重写src类的方法,是的Adapter的灵活性增强了。
5. 对象适配器
5.1 对象适配器模式介绍
- 基本思路和类适配器模式相同,只是将Adapter类作为修改,不是继承src类,而是持有src类实例,以解决兼容性的问题。即:持有src类,实现dst类接口,完成src->dst的适配。
- 根据“合成服用原则”,在系统中尽量使用关联关系来替代继承关系。
- 对象适配器模式是适配器模式常用的一种。
- 改进思路:只需改进适配器即可。
5.2 用类图来描述
5.3 上代码
5.3.1 改进适配器类
**
* @author LongXi
* @create 2021-08-11 21:14
*/
//适配器类
public class VoltageAdapter implements IVoltage5V {
//关联关系中的聚合关系
private Voltage220V voltage220V;
public VoltageAdapter(Voltage220V voltage220V) {
this.voltage220V = voltage220V;
}
@Override
public int output5V() {
int dst = 0;
if (null != voltage220V){
//获取220V电压
int src = voltage220V.output220V();
System.out.println("使用对象适配器,进行适配~");
dst = src/44;
System.out.println("适配完成,输出电压为:" + dst);
}
return dst;
}
}
5.3.2 修改测试类,其他类不变
/**
* @author LongXi
* @create 2021-08-11 21:21
*/
public class Client {
public static void main(String[] args) {
System.out.println("对象适配器模式");
Phone phone = new Phone();
phone.charging(new VoltageAdapter(new Voltage220V()));
}
}
5.3.3 运行结果
对象适配器模式
电压=220伏
使用对象适配器,进行适配~
适配完成,输出电压为:5
电压为5V,可以充电~~
5.4 对象适配器模式注意事项和细节
- 对象适配器和类适配器其实算是同一种思想,只不过实现方式不同。根据合成复用原则,使用组合替代继承,所以它解决了类适配器必须继承src的局限性问题,也不再要求dst必须是接口。
- 使用成本更低,更灵活。
6. 接口适配器模式
6.1 接口适配器模式介绍
- 一些书籍称为:适配器模式(Default Adapter Pattern)或缺省适配器模式。
- 当不需要全部实现接口提供的方法时,可先设计一个抽象类实现接口,并为该接口中每个方法提供一个默认实现(空方法),那么该抽象类的子类可有选择的覆盖父类的某些方法来实现需求。
- 适用于一个接口不想使用其所有的方法的情况。
6.2 用类图来描述
6.3 上代码
6.3.1 接口
/**
* @author LongXi
* @create 2021-08-11 22:10
*/
public interface InterFace4 {
public void m1();
public void m2();
public void m3();
public void m4();
}
6.3.2 抽象适配器,实现所有方法
/**
* @author LongXi
* @create 2021-08-11 22:11
*/
//在AbsAdapter类中,我们将InterFace4的方法进行默认实现
public abstract class AbsAdapter implements InterFace4{
@Override
public void m1() {
}
@Override
public void m2() {
}
@Override
public void m3() {
}
@Override
public void m4() {
}
}
6.3.3 测试类
/**
* @author LongXi
* @create 2021-08-11 22:13
*/
public class Client {
public static void main(String[] args) {
AbsAdapter absAdapter = new AbsAdapter() {
//只需要去覆盖我们需要使用的接口方法
@Override
public void m1() {
System.out.println("覆盖了m1方法");
}
};
absAdapter.m1();
}
}
6.3.4 运行结果
覆盖了m1方法
7. 适配器在SpringMVC框架应用的源码分析
7.1 SpringMvc的HandlerAdapter,就使用了适配器模式。
7.1.1 DispatcherServlet类
8. 手写SpringMvc通过适配器设计模式获取对应Controller的源码。
- Spring定义了一个适配器接口,是的每一种Contrller有一种对应的适配器实现类
- 适配器代替controller执行相应的方法。
- 扩展Controller时,只需要增加一个适配器类就完成了SpringMvc的扩展了。
- 就是设计模式的力量。
8.1 用类图来描述
8.2 上代码
8.2.1 controller类
/**
* @author LongXi
* @create 2021-08-12 20:49
*/
public interface Controller {
}
class HttpController implements Controller{
public void doHttpHandler(){
System.out.println("http...");
}
}
class SimpleController implements Controller{
public void doSimpleHandler(){
System.out.println("Simple...");
}
}
class AnnotationController implements Controller{
public void doAnnotationHandler(){
System.out.println("Annotation...");
}
}
8.2.2 适配器类
/**
* @author LongXi
* @create 2021-08-12 20:53
*/
//定义了Adapter接口
public interface HandlerAdapter {
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{
@Override
public boolean supports(Object handler) {
return (handler instanceof HttpController);
}
@Override
public void handler(Object handler) {
((HttpController)handler).doHttpHandler();
}
}
class AnnotationHandlerAdapter implements HandlerAdapter{
@Override
public boolean supports(Object handler) {
return (handler instanceof AnnotationController);
}
@Override
public void handler(Object handler) {
((AnnotationController)handler).doAnnotationHandler();
}
}
8.2.3 DispatchServlet类
/**
* @author LongXi
* @create 2021-08-12 21:00
*/
public class DispatchServlet {
public List<HandlerAdapter> handlerAdapters = new ArrayList<HandlerAdapter>();
public DispatchServlet() {
handlerAdapters.add(new HttpHandlerAdapter());
handlerAdapters.add(new SimpleHandlerAdapter());
handlerAdapters.add(new AnnotationHandlerAdapter());
}
public void doDispatch(){
//此处模拟SpringMvc从request取handler的对象。
//适配器可以获取到希望的Controller
HttpController httpController = new HttpController();
// SimpleController simpleController = new SimpleController();
// AnnotationController annotationController = new AnnotationController();
//得到对应适配器
HandlerAdapter adapter =getHandler(httpController);
// 通过适配器执行对应的controller所对应的方法
adapter.handler(httpController);
}
public HandlerAdapter getHandler(Controller controller){
for (HandlerAdapter adapter:this.handlerAdapters){
if (adapter.supports(controller)){
return adapter;
}
}
return null;
}
public static void main(String[] args) {
new DispatchServlet().doDispatch();
}
}
8.2.4 运行结果
http...
9. 适配器模式的注意事项和细节
- 三种命名方式:是根据src是以怎么样的形式给到Adapter(在Adapter里的形式)来命名的。
- 类适配器:以类给到,在Adapter里,就是将src当作类,继承。
对象适配器:以对象给到,在Adapter里,将src作为一个对象,持有。
接口适配器:以接口给到,在Adapter里,将src作为一个接口,实现。 - Adapter模式最大的作用还是将原本不兼容的接口融合在一起工作。
- 实际开发中,实现起来不拘泥我们讲解的三种经典形式。