一天一模式之4适配器模式

初识适配器模式

定义

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

结构和说明


- Client:客户端,调用自己需要的领域接口Target。
- Target:定义客户端需要的跟特定领域相关的接口。
- Adaptee:已经存在的接口,但与客户端要求的特定领域接口不一致,需要被适配。
- Adapter:适配器,把Adaptee适配成为Client需要的Target

实例代码

定义客户端使用的接口,与特定领域相关

package cn.javass.dp.adapter.example1;
/**
 * 定义客户端使用的接口,与特定领域相关
 */
public interface Target {
    /**
     * 示意方法,客户端请求处理的方法
     */
    public void request();
}

已经存在的接口,这个接口需要被适配

package cn.javass.dp.adapter.example1;
/**
 * 已经存在的接口,这个接口需要被适配
 */
public class Adaptee {
    /**
     * 示意方法,原本已经存在,已经实现的方法
     */
    public void specificRequest() {
        //具体的功能处理
    }
}

定义客户端使用的接口,与特定领域相关

package cn.javass.dp.adapter.example1;
/**
 * 适配器
 */
public class Adapter implements Target {
    /**
     * 持有需要被适配的接口对象
     */
    private Adaptee adaptee;
    /**
     * 构造方法,传入需要被适配的对象
     * @param adaptee 需要被适配的对象
     */
    public Adapter(Adaptee adaptee) {
        this.adaptee = adaptee;
    }

    public void request() {
        //可能转调已经实现了的方法,进行适配
        adaptee.specificRequest();
    }
}

使用适配器的客户端

package cn.javass.dp.adapter.example1;
/**
 * 使用适配器的客户端
 */
public class Client {   
    public static void main(String[] args) {
        //创建需被适配的对象
        Adaptee adaptee = new Adaptee();
        //创建客户端需要调用的接口对象
        Target target = new Adapter(adaptee);
        //请求处理
        target.request();
    }
}

体会适配器模式

装配电脑的例子

1:旧的硬盘和电源

2:加入新的硬盘

3:有何问题

如果把上面的问题抽象一下,用对象来描述,那就是:有一个电源类和旧
的硬盘类配合工作得很好,现在又有了一个新的硬盘类,现在想让新的硬盘类和
电源类也配合使用,但是发现它们的接口无法匹配,问题就产生了:如何让原有
的电源类的接口能够适应新的硬盘类的电源接口的需要呢?

4:如何解决

解决方法是采用一个转接线类,转接线可以把电源的接口适配成为新的硬
盘所需要的接口,那么这个转接线类就类似本节的主角——适配器。

同时支持数据库和文件的日志管理

1:日志管理第一版

在第一版的时候,用户要求日志以文件的形式记录。

2:日志管理第二版

要采用数据库来管理日志

不用模式的解决方案

直接参看代码示例

操作第一版

日志数据对象
package cn.javass.dp.adapter.example2;

import java.io.*;

/**
 * 日志数据对象
 */
public class LogModel implements Serializable{
    /**
     * 日志编号
     */
    private String logId;
    /**
     * 操作人员
     */
    private String operateUser;
    /**
     * 操作时间,以yyyy-MM-dd HH:mm:ss的格式记录
     */
    private String operateTime; 
    /**
     * 日志内容
     */
    private String logContent;

    public String getLogId() {
        return logId;
    }
    public void setLogId(String logId) {
        this.logId = logId;
    }
    public String getOperateUser() {
        return operateUser;
    }
    public void setOperateUser(String operateUser) {
        this.operateUser = operateUser;
    }
    public String getOperateTime() {
        return operateTime;
    }
    public void setOperateTime(String operateTime) {
        this.operateTime = operateTime;
    }
    public String getLogContent() {
        return logContent;
    }
    public void setLogContent(String logContent) {
        this.logContent = logContent;
    }

    public String toString(){
        return "logId="+logId+",operateUser="+operateUser+",operateTime="+operateTime+",logContent="+logContent;
    }
}

日志文件操作接口
package cn.javass.dp.adapter.example2;

import java.util.List;
/**
 * 日志文件操作接口
 */
public interface LogFileOperateApi {
    /**
     * 读取日志文件,从文件里面获取存储的日志列表对象
     * @return 存储的日志列表对象
     */
    public List<LogModel> readLogFile();
    /**
     * 写日志文件,把日志列表写出到日志文件中去
     * @param list 要写到日志文件的日志列表
     */
    public void writeLogFile(List<LogModel> list);
}
实现对日志文件的操作
package cn.javass.dp.adapter.example2;

import java.io.*;
import java.util.*;

/**
 * 实现对日志文件的操作
 */
public class LogFileOperate implements LogFileOperateApi{
    /**
     * 日志文件的路径和文件名称,默认是当前classpath下的AdapterLog.log
     */
    private String logFilePathName = "AdapterLog.log";  
    /**
     * 构造方法,传入文件的路径和名称
     * @param logFilePathName 文件的路径和名称
     */
    public LogFileOperate(String logFilePathName) {
        //先判断是否传入了文件的路径和名称,如果是,
        //就重新设置操作的日志文件的路径和名称
        if(logFilePathName!=null && logFilePathName.trim().length()>0){
            this.logFilePathName = logFilePathName;
        }
    }
    public  List<LogModel> readLogFile() {
        List<LogModel> list = null;
        ObjectInputStream oin = null;
        try {
            File f = new File(logFilePathName);
            if(f.exists()){
                /**
                 * 使用了装配模式
                 */
                oin = new ObjectInputStream(
                        new BufferedInputStream(new FileInputStream(f))
                );
                list = (List<LogModel>)oin.readObject();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            try {
                if(oin!=null){
                    oin.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return list;
    }

    public void writeLogFile(List<LogModel> list){
        File f = new File(logFilePathName);
        ObjectOutputStream oout = null;
        try {
            oout = new ObjectOutputStream(
                    new BufferedOutputStream(new FileOutputStream(f))
            );
            oout.writeObject(list);         
        } catch (IOException e) {
            e.printStackTrace();
        }finally{
            try {
                oout.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
客户端
package cn.javass.dp.adapter.example2;
import java.util.ArrayList;
import java.util.List;

import cn.javass.dp.adapter.example3.LogDbOperateApi;
public class Client {
    public static void main(String[] args) {
        //准备日志内容,也就是测试的数据
        LogModel lm1 = new LogModel();
        lm1.setLogId("001");
        lm1.setOperateUser("admin");
        lm1.setOperateTime("2010-03-02 10:08:18");
        lm1.setLogContent("这是一个测试");

        List<LogModel> list = new ArrayList<LogModel>();
        list.add(lm1);

        //创建操作日志文件的对象
        LogFileOperateApi api = new LogFileOperate(""); 
        //保存日志文件
        api.writeLogFile(list);

        //读取日志文件的内容
        List<LogModel> readLog = api.readLogFile();
        System.out.println("readLog="+readLog);

        LogDbOperateApi api2 = null;
    }
}

操作第二版

定义操作日志的应用接口,为了示例的简单,只是简单的定义了增删改查的方法
package cn.javass.dp.adapter.example3;
import java.util.*;
/**
 * 定义操作日志的应用接口,为了示例的简单,
 * 只是简单的定义了增删改查的方法
 */
public interface LogDbOperateApi {
    /**
     * 新增日志
     * @param lm 需要新增的日志对象
     */
    public void createLog(LogModel lm);
    /**
     * 修改日志
     * @param lm 需要修改的日志对象
     */
    public void updateLog(LogModel lm);
    /**
     * 删除日志
     * @param lm 需要删除的日志对象
     */
    public void removeLog(LogModel lm);
    /**
     * 获取所有的日志
     * @return 所有的日志对象
     */
    public List<LogModel> getAllLog();
}

存在的问题

现在的客户端,无法以同样的方式来直接使用第一版的实现

使用模式的解决方案

示例代码

其他相同,添加了适配器对象

适配器对象,把记录日志到文件的功能适配成第二版需要的增删改查的功能
package cn.javass.dp.adapter.example3;

import java.util.List;

/**
 * 适配器对象,把记录日志到文件的功能适配成第二版需要的增删改查的功能
 */
public class Adapter  implements LogDbOperateApi{
    //优先使用对象组合,而不是使用对象继承

    /**
     * 持有需要被适配的接口对象
     */
    private LogFileOperateApi adaptee;


    /**
     * 构造方法,传入需要被适配的对象
     * @param adaptee 需要被适配的对象
     */
    public Adapter(LogFileOperateApi adaptee) {
        this.adaptee = adaptee;

    }

    public void createLog(LogModel lm) {

        //1:先读取文件的内容
        List<LogModel> list = adaptee.readLogFile();
        //2:加入新的日志对象
        list.add(lm);
        //3:重新写入文件
        adaptee.writeLogFile(list);
    }

    public List<LogModel> getAllLog() {
        return adaptee.readLogFile();
    }

    public void removeLog(LogModel lm) {
        //1:先读取文件的内容
        List<LogModel> list = adaptee.readLogFile();
        //2:删除相应的日志对象
        list.remove(lm);
        //3:重新写入文件
        adaptee.writeLogFile(list);
    }

    public void updateLog(LogModel lm) {
        //1:先读取文件的内容
        List<LogModel> list = adaptee.readLogFile();
        //2:修改相应的日志对象
        for(int i=0;i<list.size();i++){
            if(list.get(i).getLogId().equals(lm.getLogId())){
                list.set(i, lm);
                break;
            }
        }
        //3:重新写入文件
        adaptee.writeLogFile(list);
    }
}

客户端
package cn.javass.dp.adapter.example3;
import java.util.*;
public class Client {
    public static void main(String[] args) {
        //准备日志内容,也就是测试的数据
        LogModel lm1 = new LogModel();
        lm1.setLogId("001");
        lm1.setOperateUser("admin");
        lm1.setOperateTime("2010-03-02 10:08:18");
        lm1.setLogContent("这是一个测试");

        List<LogModel> list = new ArrayList<LogModel>();
        list.add(lm1);

        //创建操作日志文件的对象
        LogFileOperateApi logFileApi = new LogFileOperate("");

        //创建新版的操作日志的接口对象
        LogDbOperateApi api=new Adapter(logFileApi); 

//      LogDbOperateApi api = null;


        /////////////////////////真正的操作
        //保存日志文件
        api.createLog(lm1);

        //读取日志文件的内容
        List<LogModel> allLog = api.getAllLog();
        System.out.println("allLog44="+allLog);
    }
}

小结一下思路

1:原有文件存取日志的方式,运行得很好

2:现在有了新的基于数据库的实现,新的实现有自己的接口

3:现在想要在第二版的实现里面,能够同时兼容第一版的功能,那么就应有一个类

来实现第二版的接口,然后在这个类里面去调用已有的功能实现,这个类就是适
配器

理解适配器模式

认识适配器模式

1:适配器模式的功能

适配器模式的主要功能是进行转换匹配,目的是复用已有的功能,而不是
来实现新的接口。

适配器里面也可以实现功能,称这种适配器为智能适配器。

2:Adaptee和Target的关系

适配器模式中被适配的接口Adaptee和适配成为的接口Target是没有关联的

3:对象组合

适配器的实现方式其实是依靠对象组合的方式。

5:适配器模式的调用顺序示意图

适配器模式的实现

1:适配器的常见实现

适配器通常是一个类,一般会让适配器类去实现Target接口,然后在适配
器的具体实现里面调用Adaptee。

2:智能适配器

可以在适配器的实现里面,加入新功能的实现,这种适配器被称为智能适配器。

示例代码

智能适配器对象
package cn.javass.dp.adapter.example3;

import java.util.List;

/**
 * 适配器对象,把记录日志到文件的功能适配成第二版需要的增删改查的功能
 */
public class Adapter  implements LogDbOperateApi{
    //优先使用对象组合,而不是使用对象继承

    /**
     * 持有需要被适配的接口对象
     */
    private LogFileOperateApi adaptee;

    private TimeUtil adaptee2 = null;
    /**
     * 构造方法,传入需要被适配的对象
     * @param adaptee 需要被适配的对象
     */
    public Adapter(LogFileOperateApi adaptee) {
        this.adaptee = adaptee;
    }

    public void createLog(LogModel lm) {
        // 开始时间
        Long t1=System.currentTimeMillis();
        //1:先读取文件的内容
        List<LogModel> list = adaptee.readLogFile();
        //2:加入新的日志对象
        list.add(lm);
        //3:重新写入文件
        adaptee.writeLogFile(list);
        // 结束时间时间
        Long t2=System.currentTimeMillis();
        this.adaptee2.end();
        System.out.println("操作文件时间:"+(t2-t1));
    }

    public List<LogModel> getAllLog() {
        return adaptee.readLogFile();
    }

    public void removeLog(LogModel lm) {
        //1:先读取文件的内容
        List<LogModel> list = adaptee.readLogFile();
        //2:删除相应的日志对象
        list.remove(lm);
        //3:重新写入文件
        adaptee.writeLogFile(list);
    }

    public void updateLog(LogModel lm) {
        //1:先读取文件的内容
        List<LogModel> list = adaptee.readLogFile();
        //2:修改相应的日志对象
        for(int i=0;i<list.size();i++){
            if(list.get(i).getLogId().equals(lm.getLogId())){
                list.set(i, lm);
                break;
            }
        }
        //3:重新写入文件
        adaptee.writeLogFile(list);
    }
}

3:适配多个Adaptee

示例代码

其他不变,添加一个时间接口

时间接口
package cn.javass.dp.adapter.example3;

public class TimeUtil {
    private long a1;
    private long a2;

    public void begin(){
        a1 = System.currentTimeMillis();
    }
    public void end(){
        a2 = System.currentTimeMillis();
    }
    public void show(){
        System.out.println("times11==="+(a2-a1));
    }
}

适配器对象
package cn.javass.dp.adapter.example3;

import java.util.List;

/**
 * 适配器对象,把记录日志到文件的功能适配成第二版需要的增删改查的功能
 */
public class Adapter  implements LogDbOperateApi{
    //优先使用对象组合,而不是使用对象继承

    /**
     * 持有需要被适配的接口对象
     */
    private LogFileOperateApi adaptee;

    private TimeUtil adaptee2 = null;
    /**
     * 构造方法,传入需要被适配的对象
     * @param adaptee 需要被适配的对象
     */
    public Adapter(LogFileOperateApi adaptee,TimeUtil times) {
        this.adaptee = adaptee;
        this.adaptee2 = times;
    }

    public void createLog(LogModel lm) {
        this.adaptee2.begin();
        //1:先读取文件的内容
        List<LogModel> list = adaptee.readLogFile();
        //2:加入新的日志对象
        list.add(lm);
        //3:重新写入文件
        adaptee.writeLogFile(list);
        this.adaptee2.end();
        this.adaptee2.show();
    }

    public List<LogModel> getAllLog() {
        return adaptee.readLogFile();
    }

    public void removeLog(LogModel lm) {
        //1:先读取文件的内容
        List<LogModel> list = adaptee.readLogFile();
        //2:删除相应的日志对象
        list.remove(lm);
        //3:重新写入文件
        adaptee.writeLogFile(list);
    }

    public void updateLog(LogModel lm) {
        //1:先读取文件的内容
        List<LogModel> list = adaptee.readLogFile();
        //2:修改相应的日志对象
        for(int i=0;i<list.size();i++){
            if(list.get(i).getLogId().equals(lm.getLogId())){
                list.set(i, lm);
                break;
            }
        }
        //3:重新写入文件
        adaptee.writeLogFile(list);
    }
}

4:适配器Adapter实现的复杂程度

适配器Adapter实现的复杂程度,取决于Target和Adaptee的相似程度。

5:缺省适配

缺省适配的意思是:为一个接口提供缺省实现。

示例代码

默认缺省适配器
package cn.javass.dp.adapter.example3;

import java.util.List;
/**
 * 默认缺省适配器为部分功能提供实现,
 * 其他未实现功能交由子类适配器实现
  *
 */
public class DefaultAdapter implements LogDbOperateApi{

    @Override
    public void createLog(LogModel lm) {
        System.out.println("DB createLog===========");
    }

    @Override
    public void updateLog(LogModel lm) {
        System.out.println("DB updateLog===========");
    }

    @Override
    public void removeLog(LogModel lm) {

    }

    @Override
    public List<LogModel> getAllLog() {
        return null;
    }

}
缺省适配器
package cn.javass.dp.adapter.example3;

import java.util.List;
/**
 * 缺省适配器:
 * 需要功能重新实现的可覆盖父适配器,
 * 不覆盖则为使用父类适配器功能
  *
 */
public class MyAdapter extends DefaultAdapter{
    /**
     * 持有需要被适配的接口对象
     */
    private LogFileOperateApi adaptee;

    private TimeUtil adaptee2 = null;
    /**
     * 构造方法,传入需要被适配的对象
     * @param adaptee 需要被适配的对象
     */
    public MyAdapter(LogFileOperateApi adaptee,TimeUtil times) {
        this.adaptee = adaptee;
        this.adaptee2 = times;
    }



    public List<LogModel> getAllLog() {
        return adaptee.readLogFile();
    }

    public void removeLog(LogModel lm) {
        //1:先读取文件的内容
        List<LogModel> list = adaptee.readLogFile();
        //2:删除相应的日志对象
        list.remove(lm);
        //3:重新写入文件
        adaptee.writeLogFile(list);
    }


}

双向适配器

适配器也可以实现双向的适配,前面我们讲的都是把Adaptee适配成为
Target,其实也可以把Target适配成为Adaptee,也就是说这个适配器可以同时
当作Target和Adaptee来使用。

示例代码

双向适配器对象

package cn.javass.dp.adapter.example4;

import java.util.List;

/**
 * 双向适配器对象
 */
public class TwoDirectAdapter implements LogDbOperateApi,LogFileOperateApi{
    /**
     * 持有需要被适配的文件存储日志的接口对象
     */
    private LogFileOperateApi fileLog;
    /**
     * 持有需要被适配的DB存储日志的接口对象
     */
    private LogDbOperateApi  dbLog;
    /**
     * 构造方法,传入需要被适配的对象
     * @param fileLog 需要被适配的文件存储日志的接口对象
     * @param dbLog 需要被适配的DB存储日志的接口对象
     */
    public TwoDirectAdapter(LogFileOperateApi fileLog,LogDbOperateApi dbLog) {
        this.fileLog = fileLog;
        this.dbLog = dbLog;
    }
/*-----以下是把文件操作的方式适配成为DB实现方式的接口-----*/  
    public void createLog(LogModel lm) {
        //1:先读取文件的内容
        List<LogModel> list = fileLog.readLogFile();
        //2:加入新的日志对象
        list.add(lm);
        //3:重新写入文件
        fileLog.writeLogFile(list);
    }

    public List<LogModel> getAllLog() {
        return fileLog.readLogFile();
    }

    public void removeLog(LogModel lm) {
        //1:先读取文件的内容
        List<LogModel> list = fileLog.readLogFile();
        //2:删除相应的日志对象
        list.remove(lm);
        //3:重新写入文件
        fileLog.writeLogFile(list);
    }

    public void updateLog(LogModel lm) {
        //1:先读取文件的内容
        List<LogModel> list = fileLog.readLogFile();
        //2:修改相应的日志对象
        for(int i=0;i<list.size();i++){
            if(list.get(i).getLogId().equals(lm.getLogId())){
                list.set(i, lm);
                break;
            }
        }
        //3:重新写入文件
        fileLog.writeLogFile(list);
    }
    public void removeAll(){
        System.out.println("now in two direct remove all");
    }
/*-----以下是把DB操作的方式适配成为文件实现方式的接口-----*/
    public List<LogModel> readLogFile() {
        return dbLog.getAllLog();
    }

    public void writeLogFile(List<LogModel> list) {
        //1:最简单的实现思路,先删除数据库中的数据
        dbLog.removeAll();
        //2:然后循环把现在的数据加入到数据库中
        for(LogModel lm : list){
            dbLog.createLog(lm);
        }       
    }
}

客户端

package cn.javass.dp.adapter.example4;
import java.util.*;
public class Client {
    public static void main(String[] args) {
        //准备日志内容,也就是测试的数据
        LogModel lm1 = new LogModel();
        lm1.setLogId("001");
        lm1.setOperateUser("admin");
        lm1.setOperateTime("2010-03-02 10:08:18");
        lm1.setLogContent("这是一个测试");

        List<LogModel> list = new ArrayList<LogModel>();
        list.add(lm1);

        //创建操作日志文件的对象
        LogFileOperateApi fileLogApi = new LogFileOperate("");
        LogDbOperateApi dbLogApi = new LogDbOperate();

        //创建经过双向适配后的操作日志的接口对象
        LogFileOperateApi fileLogApi2 = new TwoDirectAdapter(fileLogApi,dbLogApi); 
        LogDbOperateApi dbLogApi2 = new TwoDirectAdapter(fileLogApi,dbLogApi); 

        //先测试从文件操作适配到第二版,虽然调用的是第二版的接口,其实是文件操作在实现
        dbLogApi2.createLog(lm1);
        List<LogModel> allLog = dbLogApi2.getAllLog();
        System.out.println("allLog555="+allLog);

        //再测试从数据库存储适配成第一版的接口,也就是调用第一版的接口,其实是数据实现
        System.out.println("--------------------------->File Api  ");
        fileLogApi2.writeLogFile(list);
        fileLogApi2.readLogFile();
    }
}

对象适配器和类适配器

1:对象适配器的实现:

依赖于对象组合。就如同前面的实现示例,都是采用的对象
组合的方式,也就是前面讲述的都是对象适配器实现的方式。

2:类适配器的实现:

采用多重继承对一个接口与另一个接口进行匹配。由于Java不
支持多重继承,所以到目前为止,还没有涉及到。

类适配器的结构图如下:

Java中类似实现类适配器

示例代码
类适配器对象
package cn.javass.dp.adapter.example5;

import java.util.List;

/**
 * 类适配器对象
 */
public class ClassAdapter extends LogFileOperate implements LogDbOperateApi{

    public ClassAdapter(String logFilePathName) {
        super(logFilePathName);
    }

    public void createLog(LogModel lm) {
        //1:先读取文件的内容
        List<LogModel> list = this.readLogFile();
        //2:加入新的日志对象
        list.add(lm);
        //3:重新写入文件
        this.writeLogFile(list);
    }

    public List<LogModel> getAllLog() {
        return this.readLogFile();
    }

    public void removeLog(LogModel lm) {
        //1:先读取文件的内容
        List<LogModel> list = this.readLogFile();
        //2:删除相应的日志对象
        list.remove(lm);
        //3:重新写入文件
        this.writeLogFile(list);
    }

    public void updateLog(LogModel lm) {
        //1:先读取文件的内容
        List<LogModel> list = this.readLogFile();
        //2:修改相应的日志对象
        for(int i=0;i<list.size();i++){
            if(list.get(i).getLogId().equals(lm.getLogId())){
                list.set(i, lm);
                break;
            }
        }
        //3:重新写入文件
        this.writeLogFile(list);
    }
}

客户端
package cn.javass.dp.adapter.example5;
import java.util.*;
public class Client {
    public static void main(String[] args) {
        //准备日志内容,也就是测试的数据
        LogModel lm1 = new LogModel();
        lm1.setLogId("001");
        lm1.setOperateUser("admin");
        lm1.setOperateTime("2010-03-02 10:08:18");
        lm1.setLogContent("这是一个测试");

        List<LogModel> list = new ArrayList<LogModel>();
        list.add(lm1);


        //创建新版的操作日志的接口对象
        LogDbOperateApi api = new ClassAdapter(""); 

        //保存日志文件
        api.createLog(lm1);

        //读取日志文件的内容
        List<LogModel> allLog = api.getAllLog();
        System.out.println("allLog="+allLog);
    }
}

思考适配器模式

类适配器和对象适配器的权衡

1:从实现上:

类适配器使用对象继承的方式,是静态的定义方式;而对象适配器使用对象组
合的方式,是动态组合的方式

2:对于类适配器:

由于适配器直接继承了Adaptee,使得适配器不能和Adaptee的子类一起工
作,因为继承是个静态的关系,当适配器继承了Adaptee过后,就不可能再去处理Adaptee
的子类了。

对于对象适配器:

允许一个Adapter和多个Adaptee,包括Adaptee和它所有的子类一
起工作。因为对象适配器采用的是对象组合的关系,只要对象类型正确,是不是子类都无
所谓。

3:对于类适配器:

适配器可以重定义Adaptee的部分行为,相当于子类覆盖父类的部分实现方
法。

对于对象适配器:

要重定义Adaptee的行为比较困难,这种情况下,需要定义
Adaptee的子类来实现重定义,然后让适配器组合子类。

4:对于类适配器:

仅仅引入了一个对象,并不需要额外的引用来间接得到Adaptee。
对于对象适配器:需要额外的引用来间接得到Adaptee。

适配器模式的优缺点

  • 1:更好的复用性
  • 2:更好的可扩展性
  • 3:过多的使用适配器,会让系统非常零乱,不容易整体进行把握

适配器模式的本质

适配器模式的本质是:==转换匹配,复用功能==

何时选用适配器模式

  • 1:如果你想要使用一个已经存在的类,但是它的接口不符合你的需求,这种情况可
    以使用适配器模式,来把已有的实现转换成你需要的接口

  • 2:如果你想创建一个可以复用的类,这个类可能和一些不兼容的类一起工作,这种
    情况可以使用适配器模式,到时候需要什么就适配什么

  • 3:如果你想使用一些已经存在的子类,但是不可能对每一个子类都进行适配,这种
    情况可以选用对象适配器,直接适配这些子类的父类就可以了

猜你喜欢

转载自blog.csdn.net/kongzhongniao/article/details/79578479