适配器模式 -- 转换匹配,复用功能

原创
2016/01/22 17:45
阅读数 230

给小白举个例子:

大家都用过macbook pro(15款)笔记本, tmd没有网线端口!没有VGA 视频输出接口 !

tmd 用网线要买转换器!开会用投影仪要买视频输出转接口!

这里的转换器和转接口就是我今天要讲的主角:适配器。



这里 我举个项目中的案例,做说明:

我现在要做个日志系统,前期功能比较单一,这里我叫它第一版,就是把日志写入文件,这个ok?

1:先整个日志类

public class LogModel {

    private String logId;
    private String operateUser;
    private String operateTime;
    private String logContent;
 get / set 省略...



2: 日志操作接口,两个简单的方法定义

public interface LogFileService {

    List<LogModel> readLogFile();

    void writeLogFile(List<LogModel> list);
}



3:日志操作实现类,这里具体实现不写了,简单举例,意思一下

public class LogFileServiceImpl implements LogFileService {
    @Override
    public List<LogModel> readLogFile() {
        System.out.println("正在读文件日志");
        return null;
    }

    @Override
    public void writeLogFile(List<LogModel> list) {
        System.out.println("正在写入文件日志");
    }
}



4:写个main函数,就当客户端测试下

LogModel logModel =  new LogModel();
        LogFileService service = new LogFileServiceImpl();
        service.writeLogFile(null);
        service.readLogFile();
        System.out.println("第一版  将日志写入文件!测试完成!");



5:运行结果:


看上去很容易,是吧,别急,我们接着来!

日志写入文件系统用了一段时间,老板需求增加了,我们要做系统升级,现在我们要把日志记录到DB 数据库中,

6:于是我就把接口定义好了,日志写入DB 接口如下:(这里不与数据库交互, 意思下示例)

public interface LogDBService {

    void createDBLog(LogModel logModel);
    void updateDBLog(LogModel logModel);
    void deleteDBLog(String logId);
    void selectDBLog(LogModel logModel);

}



public class LogDBServiceImpl implements LogDBService {

    @Override
    public void createDBLog(LogModel logModel) {
        System.out.println("DB日志插入成功");
    }

    @Override
    public void updateDBLog(LogModel logModel) {
        System.out.println("DB日志更新成功");
    }

    @Override
    public void selectDBLog(LogModel logModel) {
        System.out.println("DB日志查询成功");
    }
}



7:这个时候,老板提出了,新版日志系统能不能兼容都版本,就是文件和DB都支持?

很多同学心里一下子又答案了,当然了!当然都能支持了,但是实现方式不一定想的是相同的!

有的同学先到继承 ,对,设计个新接口,然后继承老的和新的接口功能,

但是,java继承只能继承一个不能同时继承,若果使用继承在继承实现,就不符合面向对象的原则了,!这里不多说。

上图抛个问题给大家:

7:这里就用到了适配器模式,就是我们找个适配器,就能用新接口兼容老的接口了!

这里我代码示例,把旧版接口功能适配成新版接口功能:我们先设计个适配器如下:

public class Adapter implements LogDBService {

    //被适配的对象
    private LogFileService adaptee;

    //构造方法,传入要被适配的对象
    public Adapter(LogFileService adaptee) {
        this.adaptee = adaptee;
    }

    @Override
    public void createDBLog(LogModel logModel) {
        adaptee.writeLogFile(null);
    }

    @Override
    public void updateDBLog(LogModel logModel) {
        //1;先读取
        List<LogModel> list = adaptee.readLogFile();
        for (int i = 0; i < list.size(); i++) {
            //2:修改内容
        }
        //3:重新写入
        adaptee.writeLogFile(list);
    }


    @Override
    public void selectDBLog(LogModel logModel) {
        adaptee.readLogFile();
    }
}



8:我们客户端调用也要稍微调整下:

LogModel logModel =  new LogModel();
        LogFileService fileService = new LogFileServiceImpl();
        LogDBService dbService = new Adapter(fileService);
        dbService.createDBLog(null);
        dbService.selectDBLog(logModel);
        logFileClient();
        System.out.println("文件适配成DB ,测试完成!");



结果如下:

我们使用的是第二版的接口,但实现的却是是第一版的功能,因为中间我们用到了一个适配器Adaper,

就像我们网线转换器一样,用的是USB接口,我们用它确实实现网络连接!

9: 到此我们新的客户端通过新的接口(第二版接口) ,能使用新功能,也能使用老功能了,如图:


10:老板在这时候,有提出了个需求,老的项目也要使用新版日志系统和新版日志功能,

这里有个问题了,我们老的项目,旧的客户端怎么搞?旧的只有旧接口,没有新版接口啊(读到这里,想到复制代码自己实现的同学,可以先不用学设计模式了)

这里给大家介绍个双向适配器!(上面演示的是个单向适配器),双向适配器的作用就是双向兼容!

上图示例说明:

11:双向适配器代码示例:

public class TwoDirectAdapter implements LogDBService,LogFileService{
    private LogFileService logFileAdaptee;
    private LogDBService   logDBAdaptee;

    public TwoDirectAdapter(LogFileService logFileAdaptee, LogDBService logDBAdaptee) {
        this.logFileAdaptee = logFileAdaptee;
        this.logDBAdaptee = logDBAdaptee;
    }

    @Override
    public void createDBLog(LogModel logModel) {
        logFileAdaptee.writeLogFile(null);
    }

    @Override
    public void updateDBLog(LogModel logModel) {
        //1;先读取
        List<LogModel> list = logFileAdaptee.readLogFile();
        for (int i = 0; i < list.size(); i++) {
            //2:修改内容
        }
        //3:重新写入
        logFileAdaptee.writeLogFile(null);
    }


    @Override
    public void selectDBLog(LogModel logModel) {
        logFileAdaptee.readLogFile();
    }

    @Override
    public List<LogModel> readLogFile() {
        logDBAdaptee.selectDBLog(null);
        return null;
    }

    @Override
    public void writeLogFile(List<LogModel> list) {
        logDBAdaptee.createDBLog(null);
    }
}



12:旧客户端调整代码:
//双向兼容,双向适配器
System.out.println("===========双向适配器测试开始============");
        //创建操作日志文件对象
        LogFileService fileSer = new LogFileServiceImpl();
        LogDBService dbSer = new LogDBServiceImpl();

        //创建经过双向适配器后的操作日志的接口对象
        LogFileService logFileSer =  new TwoDirectAdapter(fileSer,dbSer);
        LogDBService dbFileSer =  new TwoDirectAdapter(fileSer,dbSer);

        //调用第一版,实际是第二版实现
        logFileSer.readLogFile();
        logFileSer.writeLogFile(null);

        //调用第二版,实际是第一版实现
        dbFileSer.createDBLog(null);
        dbFileSer.selectDBLog(null);
        System.out.println("===========双向适配器测试完成============");

13:测试结果如下:利用双向适配器,旧系统也能使用新版日志系统包括其所有功能了。

15:什么场景下使用适配器?

  1. 如果你想要使用已经存在的类,但是它的接口不符合你的需求。
  2. 如果你想创建一个可复用的类,但是这个类可能和一些不兼容的类一起工作。
  3. 如果你想使用一些已存的子类,但是不可能对每个子类都进行适配。



展开阅读全文
加载中
点击引领话题📣 发布并加入讨论🔥
打赏
0 评论
2 收藏
1
分享
返回顶部
顶部