设计模式-适配器模式

设计模式-适配器模式

设计模式-适配器模式

适配器的插头

我们来看一下适配器的一个简单的代码案例

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 interface Target {
    /**
     * 示意方法,客户端请求处理的方法
     */
    public void request();
}
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();
    }
}

本质上就是对已经存在的功能进行封装,满足客户端心得需求

设计模式-适配器模式

我们现在使用一个下面的功能。将日志文件保存到文件中

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.*;
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);
    }
}

现在在后面的开发中,我们需要使用数据库的形式来保存日志,最新的保存的日志使用最新的数据库的增加

删除 更新等四个接口,所以现在存在了两个版本的日志系统,第一个版本是日志文件系统,第二个版本是数据库系统,我们需要实现操作数据库的接口能够实现操作日志

设计模式-适配器模式

设计模式-适配器模式

我们使用适配器的模式来解决下面的代码

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.example4;

import java.util.List;
/**
 * DB存储日志的实现,为了简单,这里就不去真的实现和数据库交互了,示意一下
 */
public class LogDbOperate implements LogDbOperateApi{

    public void createLog(LogModel lm) {
        System.out.println("now in LogDbOperate createLog,lm="+lm);
    }

    public List<LogModel> getAllLog() {
        System.out.println("now in LogDbOperate getAllLog");
        return null;
    }

    public void removeLog(LogModel lm) {
        System.out.println("now in LogDbOperate removeLog,lm="+lm);
    }

    public void updateLog(LogModel lm) {
        System.out.println("now in LogDbOperate updateLog,lm="+lm);
    }

}
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); 
        
        //保存日志文件
        api.createLog(lm1);
        
        //读取日志文件的内容
        List<LogModel> allLog = api.getAllLog();
        System.out.println("allLog="+allLog);
    }
}

这样就是实现采用数据库的方式来适配第一版的日志系统

适配器的主要功能:

是复用已经存在的功能,被适配的对象adaptee和需要适配成新的对象Target接口,二者是毫无关系的

设计模式-适配器模式

设计模式-适配器模式

设计模式-适配器模式