• 设计模式之适配器模式


    前言

    小六新买了一个小米6手机,它高高兴兴的拿到新手机,想要插上耳机听歌,但发现手机没有耳机孔,仔细查看说明书之后发现,小米6手机是充电孔耳机孔在一起,在插耳机时需要一个耳机转接器,才能插耳机。我们用程序员的眼观来看,这里相当于增加了一个转接器类用于适配耳机,这就类似于我们今天提到的设计模式—适配器模式。

    一、适配器模式实现

    适配器模式的类图如下所示:

    其中:

    • Client:客户端,调用自己需要的接口Target
    • Target:定义客户端需要的跟特定需求相关的接口
    • Apaptee:已存在接口,通常满足功能需求但与特定需求接口不一致
    • Adapter:适配器,将Adaptee适配为Client需要的Target接口。

    适配器模式的主要功能是进行转换匹配,用来复用已有的功能。适配器模式将某个类的接口转换成客户端期望的另一个接口,目的是消除由于接口不匹配所造成的类的兼容性问题。主要分为三类:类适配器模式、对象适配器模式、接口适配器模式

    三种适配器模式有各自的应用场景:

    • 类的适配器模式:将一个类转换成满足另一个新接口的类,创建一个新类,继承原有的类,实现新的接口即可。
    • 对象的适配器模式:将一个对象转换成满足另一个新接口的对象,可以创建一个Wrapper类,持有原类的一个实例,在Wrapper类的方法中,调用实例的方法即可。
    • 接口的适配器模式:当不希望实现一个接口中所有的方法时,可以创建一个抽象类Wrapper,实现所有方法,我们写别的类的时候,继承抽象类即可。

    下面针对三种情况进行代码实现:

    1、类适配器模式

    核心思想就是:有一个Source类,拥有一个方法,待适配,目标接口是Targetable,通过Adapter类,将Source的功能扩展到Targetable里,类图如下所示:

    代码如下:

    public class Source {   
        public void method1() {  
            System.out.println("this is original method!");  
        }  
    }  
    
    public interface Targetable {  
        /* 与原类中的方法相同 */  
        public void method1();  
        /* 新类的方法 */  
        public void method2();  
    }
    

    Adapter类继承Source类,实现Targetable接口:

    public class Adapter extends Source implements Targetable {  
        @Override  
        public void method2() {  
            System.out.println("this is the targetable method!");  
        }  
    }  
    

    这样Targetable接口的实现类就具有了Source类的功能。下面为测试类:

    public class AdapterTest {  
        public static void main(String[] args) {  
            Targetable target = new Adapter();  
            target.method1();  
            target.method2();  
        }  
    }  
    

    2、对象适配器模式

    基本思路和类的适配器模式相同,只是将Adapter类作修改,这次不继承Source类,而是持有Source类的实例,以达到解决兼容性的问题。如图:

    只需要修改Adapter类的源码即可:

    public class Wrapper implements Targetable {  
        private Source source;  
        public Wrapper(Source source){  
            super();  
            this.source = source;  
        }  
        @Override  
        public void method2() {  
            System.out.println("this is the targetable method!");  
        }    
        @Override  
        public void method1() {  
            source.method1();  
        }  
    }
    

    测试类:

    public class AdapterTest {     
        public static void main(String[] args) {  
            Source source = new Source();  
            Targetable target = new Wrapper(source);  
            target.method1();  
            target.method2();  
        }  
    } 
    

    输出与第一种一样,只是适配的方法不同而已。

    3、接口适配器模式

    接口的适配器模式是当一个接口中有多个抽象方法,但只需要使用其中某些方法,可借助一个抽象类实现该接口的所有的方法,而我们只需写一个类继承该抽象类,重写需要的方法即可。类图如下:

    示例代码如下:

    接口Sourceable:

     public interface Sourceable {      
         public void method1();  
         public void method2();  
     } 
    

    抽象类Wrapper2:

    public abstract class Wrapper2 implements Sourceable{  
        public void method1(){}  
        public void method2(){}  
    }  
    

    实现类:

    public class SourceSub1 extends Wrapper2 {  
        public void method1(){  
            System.out.println("the sourceable interface's first Sub1!");  
        }  
    } 
    
    public class SourceSub2 extends Wrapper2 {  
        public void method2(){  
            System.out.println("the sourceable interface's second Sub2!");  
        }  
    } 
    

    二、适配器模式说明

    适配器模式的本质是:转换匹配,复用功能。适配器模式中被适配的接口Adaptee与适配的接口Target没有关系,他们中的方法可以相同,也可以完全不同,适配器模式的实现方式是通过组合对象的方式进行的,将功能委托给被适配的对象进行的。

    适配器模式调用的序列图如下所示:

    适配器模式的实现有以下几种:

    • 常见适配:适配器类会实现接口,在实现过程中调用待适配的类中的方法

    • 智能适配器:在适配器类中实现接口中定义的新方法,通常来说,适配器类中既可以通过借助继承类中的方法实现高层功能,也可以实现接口中定义的新方法,进行功能扩展。

    • 缺省适配:即对接口的缺省实现,即接口适配器模式。

    此外,在适配过程中,可能接口功能的实现需要多个待适配类中的方法交互才能满足需求,即同时适配多个类。适配实现的复杂度取决于待适配类与接口的相似度,相似程度越高,适配类的实现难度越低。

    在实际项目过程中,通常会存在两个版本共存的情况,这就是需要使用到双向适配器。示例代码如下:

    两个版本的实现代码:

    public interface Targetable1 {
    	public void produce1();
    }
    public class Target1 implements Targetable1 {
    	@Override
    	public void produce1() {
    		System.out.println("Targetable1的produce1实现");
    	}
    }
    
    public interface Targetable2 {
    	public void produce2();
    }
    public class Target2 implements Targetable2 {
    	@Override
    	public void produce2() {
    		System.out.println("Targetable2的produce2实现");
    	}
    }
    

    适配器类的代码如下:

    public class Adapter implements Targetable1, Targetable2 {
    
        private Targetable1 target1;
        private Targetable2 target2;
    
        @Override
        public void produce1() {
            target1.produce1();
        }
    
        @Override
        public void produce2() {
            target2.produce2();
        }
    }
    

    实际上,在使用适配器过程中存在一个问题:被适配的对象不兼容Adapter适配器类,这使得适配器类的适用范围受到限制。而双向适配器则解决了这样的问题,可以满足不同客户采用不同方式查看同一不同对象的需求。

    三、适配器模式总结

    1、应用场景

    • 实现已实现接口的复用,利用已有的代码实现功能。
    • 使用已存在的部分子类,可选用随想适配器,适配子类的父类。

    2、优缺点

    优点

    • 更好的复用性。适配器模式可复用已实现接口的兼容。
    • 更好的扩展性。实现适配器的过程中可以调用自己开发的功能,实现系统的扩展。

    缺点

    过多使用适配器,系统会比较混乱,不易理解

    参考:文章主要参考《研磨设计模式》一书

  • 相关阅读:
    Leetcode 3:无重复字符的最长子串
    激光三角测量法在工业视觉检测上的应用
    通俗易懂的Harris 角点检测
    杂乱场景中的尺度层次三维目标识别
    多视图几何三维重建实战系列之R-MVSNet
    一文详解工业相机和镜头选取
    LOAM论文介绍与A-LOAM代码简介
    基于双目事件相机的视觉里程计
    在医学图像分析中使用ICP算法进行点云配准
    两种ICP的改进算法:PLICP与NICP
  • 原文地址:https://www.cnblogs.com/liuyi6/p/10344222.html
Copyright © 2020-2023  润新知