设计模式--适配器模式

一、什么是适配器
如果你的电器是一个两项的插头,而电源插座是三项的,那就需要一个交流电适配器。这个适配器位于两项插头和三项插座的中间,他的工作是将三项插座转成两项插座,好让两项插头可以插进这个插座得到电力,也可以说,适配器改变了插座的接口,以符合两项插头的需求。


设计模式--适配器模式_第1张图片
image.png

二、面向对象适配器
假设已有一个软件系统,希望他能和一个新的厂商类库搭配使用,但是这个新厂商所设计出来的接口,不同于旧厂商的接口:


设计模式--适配器模式_第2张图片
image.png

不改变现有代码,怎么解决这个问题呢?可以写一个类,将新厂商接口转接成所期望的接口。
设计模式--适配器模式_第3张图片
image.png

A、具体的面向对象适配器的例子

设计一个TypeC与USB的转接
1、TypeC接口

public interface TypeC {
  void isTypeC();
}

2、USB接口

public interface USB 
  void isUsb();
}

3、实现USB接口

public class Usb implements USB {
    @Override
    public void isUsb() {
        System.out.println("USB口");
    }
}

4、适配器

  //implement是想转换的类型接口,也就是客户希望看到的接口
public class UsbAdapter implements TypeC {
    USB usb;
    //取得要适配的对象的引用,这里利用构造器取得
    public UsbAdapter(USB usb) {
      This.usb = usb;
    }
    @Override
    public void isTypeC() {//实现TypeC接口中的方法,实际上调用的是usb的方法
        usb.isUsb();
    }
}

5、测试一下

public class TypeCDrive {
    public static void main(String[] args) {
        //创建一个USB
        USB usb = new USB();
        //将USB包装进USB适配器中,使他看起来像个TypeC
        TypeC usbAdapter = new UsbAdapter(usb)
        //传入一个假装是TypeC的USB
        testTypeC(usbAdapter);      
    }
    //取得TypeC并调用isTypeC方法
    static void testTypeC(TypeC typeC) {
        typeC.isTypeC();
    }
}

6、结果

USB口

可以看出当testTypeC被调用时,不知道实际传入的是一个假装TypeC的USB

B、适配器模式
将一个类的接口,转换成客户期望的另一个接口,适配器让原本接口不兼容的类可以合作无间。
面向对象适配器类图


设计模式--适配器模式_第4张图片
image.png

适配器模式使用对象组合,以修改的接口包装被适配者,被适配者的任何子类都可以搭配着适配器使用。

三、类适配器
类适配器需要多重继承才能实现,Java中是无法实现的,但是在使用多重继承语言时,可以使用它。
A、类图


设计模式--适配器模式_第5张图片
image.png

对象适配器使用组合的方式将请求传送给被适配者
类适配器采用的是继承的方式实现。

四、真实的应用
Java在早期的集合(collection)类型(如:Vector,Stack,Hashtable)都实现了一个名为elements()的方法,该方法会返回一个Enumeration。这个Enumeration接口可以循环遍历集合内的每个元素,而无需知道他们在集合内如何被管理的。


设计模式--适配器模式_第6张图片
image.png

当Sum更新集合类后,开始使用Iterator接口了,这个结婚和枚举接口很像,都可以遍历集合内元素,但是Iterator还提供了删除的功能。


设计模式--适配器模式_第7张图片
image.png

对于遗留代码,暴露出枚举的接口,但是在新代码中,只使用迭代器,要解决这个问题,就需要构造一个适配器。
那么就先看看这两个接口,都有什么关系吧,也就是说,要找出每一个适配器在被适配者中的对应方法是什么。
设计模式--适配器模式_第8张图片
image.png

类图


设计模式--适配器模式_第9张图片
image.png

因为枚举不支持删除,所以适配器无法实现一个有实际功能的remove()方法,所以讲remove()方法定义成会抛出UnsupportedOpeartionException。

实现:

//适配器需要实现迭代器的接口,让他看起来就是一个迭代器implements Iterator
public class EnumerationIterator implements Iterator {
  Enumeration enum;
  //利用组合的方式,将枚举结合进适配器中,用一个实例变量记录枚举
  public EnumerationIterator (Enumeration enum) {
    This.enum = enum;
  }
  //迭代器的hasNext()方法实际委托给枚举的hasMoreElements()方法
  public boolean hasNext() {
    return enum.hasMoreElements();
  }
  //迭代器的next()方法实际委托给枚举的nextElements()方法
  public Object next() {
    return enum.nextElement();
  }
  //无法支持迭代器的remove()的方法,只能抛出异常
  public void remove() {
    throw new UnsupportedOpeartionException();
  }
}

你可能感兴趣的:(设计模式--适配器模式)