• 设计模式-适配器模式


    适配者模式是也是android中应用很广泛的设计模式,如我们常见用 BaseAdpter, ArrayAdapter, CursorAdapter,就是用的适配者模式,看到源码你是不是对这种设计方式很陌生,没事,下面我们通过实际的例子来取理解这种设计模式。

    一、作用

    适配器模式(Adapter):将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。

    二、适用场景

    1. 业务的接口与工作的类不兼容,(比如:类中缺少实现接口的某些方法)但又需要两者一起工作

    2. 在现有接口和类的基础上为新的业务需求提供接口

    三、常见的使用方式

    还是以Usb接口和Phone手机类的产品举例子,假设设计的Phone类中有 call(), sms(), takeAlong()属性方法,而在设计Usb接口时定义了 store(), takeAlong()的行为。如果现在有新的业务需求,需要生成 Xiaomi手机类具有 Phone类和Usb接口两者功能,假设Phone类和Usb接口已经在业务上投入使用,很显然,去修改原类中的方法和接口的行为去满足现在的新业务需求是不可取的,那么现在适配者模式就派上用场了。

    (1)类适配模式

    大致的意思是新的业务类Xiaomi通过继承旧业务的类Phone并实现接口Usb来满足新的业务的一种适配方式,如下图

    Usb接口

    1. public interface Usb {  
    2.   
    3.     void store();  
    4.   
    5.     void takeAlong();  
    6. }  

    Phone类

    1. public class Phone {  
    2.   
    3.     public void call() {  
    4.         System.out.println("Phone call");  
    5.     }  
    6.   
    7.     public void sms() {  
    8.         System.out.println("Phone sms");  
    9.     }  
    10.   
    11.     public void takeAlong() {  
    12.         System.out.println("Phone takeAlong");  
    13.     }  
    14. }  

    适配 Xiaomi 类

    1. /** 
    2.  * 类的适配器模式 
    3.  * phone + Usb 
    4.  * 将Phone的功能扩展到Usb里 
    5.  * @author xuzhaohu 
    6.  *  
    7.  */  
    8. public class Xiaomi extends Phone implements Usb {  
    9.   
    10.     @Override  
    11.     public void store() {  
    12.         // TODO Auto-generated method stub  
    13.         System.out.println("store implements usb");  
    14.     }  
    15.   
    16. }  

    适配完后使用

    1. Xiaomi mi1 = new Xiaomi();  
    2. mi1.takeAlong();  
    3. mi1.store();  

    输出:

    Phone takeAlong
    store implements usb

    这样新的业务需求就可以通过适配的 Xiaomi类去满足了。是不是觉得很简单呢!!:)  有没有其他的方式去实现同样的功能呢?当然有,就是下面要讲的对象适配模式。

    (2)对象适配模式

    实现的方式很简单,其实就是在适配的时候通过构造函数将旧的业务Phone 当作新的适配类(XiaomiWrapper)一个成员对象去处理,然后适配类只需要实现接口 Usb即可。如下类关系图

    适配类XiaomiWrapper如下,注意takeAlong()方法,是直接调用原类对象(Phone)去执行的。

    1. /** 
    2.  * 对象的适配器模式 
    3.  *  
    4.  * @author xuzhaohu 
    5.  *  
    6.  */  
    7. public class XiaomiWrapper implements Usb {  
    8.   
    9.     /** 
    10.      * 1.创建一个Wrapper类,持有原类的一个实例, 
    11.      * 2.在Wrapper类的方法中,调用实例的方法就行 
    12.      */  
    13.     private Phone phone;  
    14.   
    15.     public XiaomiWrapper(Phone phone) {  
    16.   
    17.         this.phone = phone;  
    18.     }  
    19.   
    20.     @Override  
    21.     public void store() {  
    22.         // TODO Auto-generated method stub  
    23.         System.out.println("store implements usb");  
    24.   
    25.     }  
    26.   
    27.     @Override  
    28.     public void takeAlong() {  
    29.         // TODO Auto-generated method stub  
    30.         phone.takeAlong();  
    31.     }  
    32.   
    33. }  

    适配完后通过构造函数将原对象传入即可。

    1. XiaomiWrapper mi2 = new XiaomiWrapper(new Phone());  
    2. mi2.takeAlong();  
    3. mi2.store();  

    输出:

    Phone takeAlong
    store implements usb

    或许到这里,你会觉得这种方式很简单吧。但是如果出现这个Usb接口中有很多方法(大于2个),但是新的业务需求中也只需要其中的一两个,而且是需要适配很多这样的业务,这样的话,用上面的方法每次适配一次就会去实现所有Usb接口中的方法,实际上适配的类中有很多是用不到的,没有必要把接口中不使用的类也适配进去,这时候,就轮到下面的接口适配模式出场了。

    (3)接口适配模式

    适配新的业务需求的时候借助抽象实现类(AbsPhone实现Usb接口),也就说,抽象实现类把Usb接口中的行为都实现了,新的适配是需要跟抽象类对话就行,因为抽象实现类就能满足了所有适配的需求,并且做到了只适配业务本身的行为,接口中不需要的行为我根本不需要关注。这就是抽象实现类的作用。类图关系如下:

    抽象类AbsPhone实现

    1. /** 
    2.  * 接口的适配器模式 
    3.  * 1.借助于一个抽象类,该抽象类实现了该接口,实现了所有的方法 
    4.  * 2.继承类可以选择性的实现接口中的方法 
    5.  *  
    6.  * @author xuzhaohu 
    7.  *  
    8.  */  
    9. public abstract class AbsPhone implements Usb {  
    10.   
    11.     public void store() {  
    12.         System.out.println("AbsPhone implements usb's store methond");  
    13.     }  
    14.   
    15.     public void takeAlong() {  
    16.         System.out.println("AbsPhone implements usb's takeAlong methond");  
    17.     }  
    18. }  

    适配类只跟AbsPhone打交道,根本不需要关心接口的行为,只显示自己所要关注的。

    如Phone1适配只需要store()行为

    1. public class Phone1 extends AbsPhone {  
    2.   
    3.     public void call() {  
    4.         System.out.println("Phone1 call");  
    5.     }  
    6.       
    7.     public void sms() {  
    8.         System.out.println("Phone1 sms");  
    9.     }  
    10.   
    11.     public void store() {  
    12.         System.out.println("Phone1 need usb's store methond");  
    13.     }  
    14.   
    15. }  

    Phone2适配只需要takeAlong()行为

    1. public class Phone2 extends AbsPhone {  
    2.   
    3.     public void call() {  
    4.         System.out.println("Phone2 call");  
    5.     }  
    6.   
    7.     public void sms() {  
    8.         System.out.println("Phone2 sms");  
    9.     }  
    10.   
    11.     public void takeAlong() {  
    12.         System.out.println("Phone2 need usb's takeAlong methond");  
    13.     }  
    14.   
    15. }  

    实例化调用

    1. Phone1 p1 = new Phone1();  
    2. Phone2 p2 = new Phone2();  
    3. p1.store();  
    4. p2.takeAlong();  

    输出:

    Phone1 need usb's store methond
    Phone2 need usb's takeAlong methond

    来一次完整的调用

    1. Phone1 p1 = new Phone1();  
    2. Phone2 p2 = new Phone2();  
    3. p1.store();  
    4. p1.takeAlong();  
    5. p2.takeAlong();  
    6. p2.store();  

    输出:

    Phone1 need usb's store methond
    AbsPhone implements usb's takeAlong methond
    Phone2 need usb's takeAlong methond
    AbsPhone implements usb's store methond

    这样很清晰的知道适配的什么方法了。

  • 相关阅读:
    构造函数与其他类方法的区别
    将博客搬至51CTO
    易错点
    c++类构造函数详解
    将博客搬至CSDN
    实数,有理数,无理数,自然数,整数的概念分别是什么?
    code for qint function
    spline和Pchips的不同(matlab)
    Pseudocode MD5 CODE
    git基础介绍
  • 原文地址:https://www.cnblogs.com/wangzehuaw/p/4760173.html
Copyright © 2020-2023  润新知