适配器模式(Adapter)

1.模式的定义:

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

适配器模式的分类:

  • 通过继承实现Adapter (继承Adaptee)—类适配器
  • 通过委让实现Adapter (包含Adaptee对象)—对象适配器

结构图:

2.模式的UML图

Client: 调用自己需要的领域接口Target

Target: 定义客户端需要的特定领域相关的接口

Adaptee: 已经存在的接口,通常能满足客户端的功能要求,但接口与客户端的要求特定领域接口不一致,需要被适配

Adapter: 适配器,把Adaptee适配成Client需要的Target

相关代码:

/**
 * 使用适配器的客户端
 */public class Client {   
    public static void main(String[] args) {        //创建需被适配的对象
        Adaptee adaptee = new Adaptee();        //创建客户端需要调用的接口对象
        Target target = new Adapter(adaptee);        //请求处理
        target.request();
    }
}/**
 * 定义客户端使用的接口,与特定领域相关
 */public interface Target {
    /**
     * 示意方法,客户端请求处理的方法
     */
    public void request();
}/**
 * 适配器
 */public class Adapter implements Target {
    /**
     * 持有需要被适配的接口对象
     */
    private Adaptee adaptee;    /**
     * 构造方法,传入需要被适配的对象
     * @param adaptee 需要被适配的对象
     */
    public Adapter(Adaptee adaptee) {        this.adaptee = adaptee;
    }    public void request() {        //可能转调已经实现了的方法,进行适配
        adaptee.specificRequest();
    }
}/**
 * 已经存在的接口,这个接口需要被适配
 */public class Adaptee {
    /**
     * 示意方法,原本已经存在,已经实现的方法
     */
    public void specificRequest() {        //具体的功能处理
    }
}

3. 研磨设计模式

转接线可以把电源的接口适配成为新的硬盘所需要的接口,转接线的角色就是适配器(Adapter)

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

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

对象适配器和类适配器的权衡: 1. 类适配器使用类继承的方式,对象适配器使用对象组合的方式 2. 对于对象适配器,一个适配器可以把多种不同的源适配到同一个目标。换言之,同一个适配器可以把源类和它的子类都适配到目标接口。 3. 对于对象适配器,需要额外的引用来间接得到Adaptee。 对于对象适配器,要重定义Adaptee的行为比较困难 4. 建议尽量使用对象适配器的实现方式,多用合成/聚合、少用继承。

1)缺省适配器

缺省适配(Default Adapter)模式为一个接口提供缺省实现,这样子类型可以从这个缺省实现进行扩展,而不必从原有接口进行扩展。 就是一个抽象类对功能接口的所有功能做空实现 然后子类继承这个抽象类 这样就可以对部分功能进行实现或拓展了

2) 日志管理系统

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); 

        //保存日志文件
        api.createLog(lm1);        //读取日志文件的内容
        List<LogModel> allLog = api.getAllLog();
        System.out.println("allLog="+allLog);
    }
}/**
 * 适配器对象,把记录日志到文件的功能适配成第二版需要的增删改查的功能
 */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);
    }
}/**
 * 定义操作日志的应用接口,为了示例的简单,
 * 只是简单的定义了增删改查的方法
 */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();
}/**
 * 实现对日志文件的操作
 */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 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 FileOutputStream(f));
            oout.writeObject(list);         
        } catch (IOException e) {
            e.printStackTrace();
        }finally{            try {
                oout.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}/**
 * 日志文件操作接口
 */public interface LogFileOperateApi {
    /**
     * 读取日志文件,从文件里面获取存储的日志列表对象
     * @return 存储的日志列表对象
     */
    public List<LogModel> readLogFile();    /**
     * 写日志文件,把日志列表写出到日志文件中去
     * @param list 要写到日志文件的日志列表
     */
    public void writeLogFile(List<LogModel> list);
}/**
 * 日志数据对象
 */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;
    }
}

原文发布于微信公众号 - JAVA高级架构(gaojijiagou)

原文发表时间:2018-04-22

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏向治洪

Android数据库Realm实践

Android开发中常用的数据库有5个: 1. OrmLite OrmLite 不是 Android 平台专用的ORM框架,它是Java ORM。支持JDBC连...

26090
来自专栏chenssy

这些Spring中的设计模式,你都知道吗?

设计模式作为工作学习中的枕边书,却时常处于勤说不用的尴尬境地,也不是我们时常忘记,只是一直没有记忆。

10310
来自专栏技术小黑屋

系统剖析Android中的内存泄漏

作为Android开发人员,我们或多或少都听说过内存泄漏。那么何为内存泄漏,Android中的内存泄漏又是什么样子的呢,本文将简单概括的进行一些总结。

11130
来自专栏Android源码框架分析

Android Studio Profiler Memory (内存分析工具)的简单使用及问题

Memory Profiler 是 Android Studio自带的内存分析工具,可以帮助开发者很好的检测内存的使用,在出现问题时,也能比较方便的分析定位问题...

44230
来自专栏Java呓语

DataBinding·常用注解说明

Observable接口提供给开发者添加/移除监听者的机制。为了使开发更便捷,我们创建了BaseObservable类,它已经实现了Observable接口中的...

14740
来自专栏求索之路

Android源码设计模式解析与实战笔记

1.单一职责原则:比如说一个ImageLoader,需要加载图片的缓存图片,此时如果将这两个功能都放在一个类中,就违反了这个原则, 我们需要将不同的功能用类精...

46750
来自专栏我就是马云飞

Architecture Components ViewModel的控制。

前言 作为MVVM 系列的第二篇,我们来看一下之前提出的第二个问题,就是ViewModel是如果控制生命周期的,并且保证在一定范围内的唯一性。 ViewMode...

17490
来自专栏developerHaoz 的安卓之旅

Android 关于内存泄露,你必须了解的东西

内存管理的目的就是让我们在开发过程中有效避免我们的应用程序出现内存泄露的问题。内存泄露相信大家都不陌生,我们可以这样理解:「没有用的对象无法回收的现象就是内存泄...

7410
来自专栏JackieZheng

照虎画猫写自己的Spring——依赖注入

前言 上篇《照虎画猫写自己的Spring》从无到有讲述并实现了下面几点 声明配置文件,用于声明需要加载使用的类 加载配置文件,读取配置文件 解析配置文件,需要将...

20880
来自专栏郭霖

Android图片加载框架最全解析(四),玩转Glide的回调与监听

大家好,今天我们继续学习Glide。 在上一篇文章当中,我带着大家一起深入探究了Glide的缓存机制,我们不光掌握了Glide缓存的使用方法,还通过源码分析对缓...

64060

扫码关注云+社区

领取腾讯云代金券