软件设计模式--第三章 结构型模式--适配器模式


第三章 结构型模式

1、结构型模式概述

结构型模式描述如何将类或对象按某种布局组成更大的结构。

  • 类结构型模式:采用继承机制来组织接口和类,
  • 对象结构型模式:采用组合或聚合来组合对象。
  • 由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象结构型模式比类结构型模式具有更大的灵活性。

结构型模式分为以下7种:

  1. 代理(Proxy)模式:客户端通过代理间接地访问该对象,从而限制、增强或修改该对象的一些特性。

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

  3. 桥接(Bridge)模式:将抽象与实现分离,使他们可以独立的变化。用组合关系代替继承关系来实现,从而降低了抽象和实现这2个可变维度的耦合度。

  4. 装饰(Decorator)模式:动态的给对象增加一些职责,即增加其额外的功能。

  5. 外观(Facade)模式:为多个复杂的子系统提供一个一致的接口, 使这些子系统更加容易被访问。

  6. 享元(Flyweight)模式:运用共享技术来有效地支持大量细粒度 对象的复用

  7. 组合(Composite)模式将对象组合成树状层次结构,使用户对单个对象和组合对象具有一致的访问性。

注:以上7种结构型模式,除了适配器模式分为类结构型模式和对象结构型模式2种,其他的全部属于对象结构型模式。


2、适配器模式

(1)模式的定义与特点

  1. 定义:将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类能一起工作。

在这里插入图片描述

  1. 适配器模式分为类适配器模式对象适配器模式

  2. 优点:

    • 客户端通过适配器可以透明地调用目标接口
    • 程序员不需要修改原有代码而重用现有的适配者类;
    • 将目标类和适配者类解耦,解决了目标类和适配者类接口不 一致的问题。
  3. 缺点:对于类适配器来说,更换适配器的实现过程比较复杂

(2)模式的结构与实现

  1. 结构
  • 目标(Target)接口:当前系统业务所期待的接口,它可以是抽象类或接口。(适配后实现的业务)
  • 适配者(Adaptee)类:它是被访问和适配的现存组件库中的组件接口。(要被适配的对象)
  • 适配器(Adapter)类:它是一个转换器,通过继承或引用适配者的对象,把适配者接口转换成目标接口,让客户按目标接口的格式访问适配者。(转换器)
  1. 实现
(1)类适配器模式

实现方式:定义一个适配器类来实现当前系统的业务接口,同时又继承现有组件库中已经存在的组件。

结构图如下:
在这里插入图片描述
例:读卡器

现有一台电脑只能读取SD卡,而要读取TF卡中的内容的话就需要使用到适配器模式。创建一个读卡器,将TF卡中的内容读取出来。

在这里插入图片描述

代码如下:

SD卡的接口:目标接口

public interface SDCard {
    //读取SD卡方法
    String readSD();
    //写入SD卡功能
    void writeSD(String msg);
}


SD卡实现类

public class SDCardImpl implements SDCard {
    public String readSD() {
        String msg = "sd card read a msg :hello word SD";
        return msg;
    }public void writeSD(String msg) {
        System.out.println("sd card write msg : " + msg);
    }
}


电脑类:可以读取SD卡

public class Computer {public String readSD(SDCard sdCard) {
        if(sdCard == null) {
            throw new NullPointerException("sd card null");
        }
        return sdCard.readSD();
    }
}


TF卡接口

public interface TFCard {
    //读取TF卡方法
    String readTF();
    //写入TF卡功能
    void writeTF(String msg);
}

TF卡实现类

public class TFCardImpl implements TFCard {public String readTF() {
        String msg ="tf card read msg : hello word tf card";
        return msg;
    }public void writeTF(String msg) {
        System.out.println("tf card write a msg : " + msg);
    }
}


定义适配器类(SD兼容TF):转换器,继承适配者类TFCardImpl 同时实现目标接口SDCard

public class SDAdapterTF extends TFCardImpl implements SDCard {public String readSD() {
        System.out.println("adapter read tf card ");
        // 调用 TFCardImpl 的方法并返回
        return readTF();
    }public void writeSD(String msg) {
        System.out.println("adapter write tf card");
        writeTF(msg);
    }
}


测试类

public class Client {
    public static void main(String[] args) {
    	// 1. 创建电脑类
        Computer computer = new Computer();
        // 2. 创建SD卡
        SDCard sdCard = new SDCardImpl();
        // 3. 电脑读取SD卡
        System.out.println(computer.readSD(sdCard));System.out.println("------------");// 创建适配器(SD卡适配TF卡)
        SDAdapterTF adapter = new SDAdapterTF();
        // 通过适配器,电脑读取TF卡
        System.out.println(computer.readSD(adapter));
    }
}
  • 类适配器模式违背了合成复用原则。类适配器是客户类有一个接口规范的情况下可用,反之不可用。
  • 也就是说没有定义SDCard 这个接口的话就不能实现了。因为适配器已经继承了适配者类,不能再继承其他类了。也就是不能通过继承SDCardImpl来实现

(2)对象适配器模式

实现方式:对象适配器模式可釆用将现有组件库中已经实现的组件引入(聚合)适配器类中该类同时实现当前系统的业务接口。

结构图如下:
在这里插入图片描述
例:读卡器

使用对象适配器模式将读卡器的案例进行改写

在这里插入图片描述

代码如下:
类适配器模式的代码,我们只需要修改**适配器类(SDAdapterTF)**和测试类。

创建适配器对象(SD兼容TF)

public class SDAdapterTF  implements SDCard {// 把TFCard 聚合进来
    private TFCard tfCard;public SDAdapterTF(TFCard tfCard) {
        this.tfCard = tfCard;
    }public String readSD() {
        System.out.println("adapter read tf card ");
        // 这里通过成员变量tfCard调用
        return tfCard.readTF();
    }public void writeSD(String msg) {
        System.out.println("adapter write tf card");
        tfCard.writeTF(msg);
    }
}


//测试类

public class Client {
    public static void main(String[] args) {
        Computer computer = new Computer();
        SDCard sdCard = new SDCardImpl();
        System.out.println(computer.readSD(sdCard));System.out.println("------------");// 1、先创建TFCard (适配者对象)
        TFCard tfCard = new TFCardImpl();
        // 2、放入适配器中进行适配
        SDAdapterTF adapter = new SDAdapterTF(tfCard);
        // 3、电脑通过 
        System.out.println(computer.readSD(adapter));
    }
}

注意:还有一个适配器模式是接口适配器模式。当不希望实现一个接口中所有的方法时,可以创建一个抽象类Adapter ,实现所有方法。而此时我们只需要继承该抽象类即可。

(3)应用场景

  • 以前开发的系统存在满足新系统功能需求的类,但其接口同新系统的接口不一致。使用适配器让新旧系统无缝连接。
  • 使用第三方提供的组件,但组件接口定义和自己要求的接口定义不同。第三方组件接口是无法修改的,使用适配器让第三方接口和自己的接口进行对接

(4)扩展

  • 适配器模式可扩展为 **双向适配器模式,**双向适配器类既可以把适配者接 口转换成目标接口,也可以把目标接口转换成适配者接口。
    在这里插入图片描述

JDK源码解析:

Reader(字符流)、InputStream(字节流)的适配使用的是InputStreamReader(字节转换为字符)

InputStreamReader继承自java.io包中的Reader,对他中的抽象的未实现的方法给出实现。
如:

public int read() throws IOException {
    return sd.read();
}public int read(char cbuf[], int offset, int length) throws IOException {
    return sd.read(cbuf, offset, length);
}

如上代码中的sd(StreamDecoder类对象),在Sun的JDK实现中,实际的方法实现是对sun.nio.cs.StreamDecoder类的同名方法的调用封装。
类结构图如下:
在这里插入图片描述

从上图可以看出:

  • InputStreamReader是对同样实现了ReaderStreamDecoder的封装。
  • StreamDecoder不是Java SE API中的内容,是Sun JDK给出的自身实现。但我们知道他们对构造方法中的字节流类(InputStream)进行封装,并通过该类进行了字节流和字符流之间的解码转换。

结论:

  • 从表层来看,InputStreamReader做了InputStream字节流类到Reader字符流之间的转换。
  • 而从如上Sun JDK中的实现类关系结构中可以看出,是StreamDecoder的设计实现在实际上采用了适配器模式。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

绿箭柠檬茶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值