目录
理解
转换头/转接线
场景
我现在有个接口,对一个日志文件进行读写操作并保存在本地,使用了一段时间后,我又新增了一个版本,这个版本的功能是增删改查并且把日志存储到数据库。
我现在想能不能让第二版实现 同时支持数据库存储和文件存储两种方式呢?
问题思考
1.如果在第二版的代码上重写文件存储方法,这样做确实可以,但是何必要重新做已经完成的功能呢?应该想办法复用,而不是重新实现
2.将两种合并起来不就可以了? 问题在于现在的业务使用的是第二版的接口,但对于第一版文件存储方式,操作接口和第二版不一样,无法以同样的方式来直接使用第一版的实现
解决方案
采用适配器
定义
解决思路
分析上面的问题,根源在于接口的不兼容,功能是基本实现了的,也就是说想办法让两边的接口匹配起来,就可以复用第一版的功能了
操作方法
定义一个类来实现第二版的接口,在内部实现的时候,转调第一版已经实现的功能,这样就可以通过对象组合的方式,既复用了第一版已有的功能,又满足了第二版调用的要求。
代码示例
1.定义数据对象
package day03适配器模式;
import java.io.Serializable;
/**
* 日志数据对象
*/
public class LogModel implements Serializable {
/**
* 日志编号
*/
private String logId;
/**
* 操作人
*/
private String operateUser;
/**
* 日志内容
*/
private String logData;
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 getLogData() {
return logData;
}
public void setLogData(String logData) {
this.logData = logData;
}
@Override
public String toString() {
return "LogModel{" +
"logId='" + logId + '\'' +
", operateUser='" + operateUser + '\'' +
", logData='" + logData + '\'' +
'}';
}
}
2.定义原接口
package day03适配器模式;
import java.util.List;
/**
* 操作日志文件的接口
*/
public interface LogFileOperateApi {
/**
* 读取日志文件,从文件里面获取存储的日志列表对象
* @return
*/
public List<LogModel> readLogFile();
/**
* 写日志文件,把日志列表写出到日志文件中去
* @param list
*/
public void writeLogFile(List<LogModel> list);
}
3.定义原实现
package day03适配器模式;
import java.io.*;
import java.util.List;
/**
* 实现对日志文件的操作
*/
public class LogFileOperateImpl implements LogFileOperateApi{
/**
* 日志文件的路径和文件名称,默认是当前项目根下的zsp.log
*/
private String logFilePathName = "zsp.log";
/**
* 构造方法,传入文件的路径和名称
* @param logFilePathName 文件的路径和名称
*/
public LogFileOperateImpl(String logFilePathName){
if (logFilePathName != null && logFilePathName.trim().length() > 0){
this.logFilePathName = logFilePathName;
}
}
@Override
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;
}
@Override
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 (Exception e) {
e.printStackTrace();
} finally {
try {
if (oout != null) {
oout.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
4.客户端实现
package day03适配器模式;
import java.util.ArrayList;
import java.util.List;
public class Client {
public static void main(String[] args) {
LogModel lml = new LogModel();
lml.setLogId("001");
lml.setOperateUser("admin");
lml.setLogData("这是日志内容");
List<LogModel> list = new ArrayList<>();
list.add(lml);
// 创建操作日志文件的对象
LogFileOperateApi api = new LogFileOperateImpl("");
// 保存日志文件
api.writeLogFile(list);
//读取日志文件的内容
List<LogModel> readLog = api.readLogFile();
System.out.println("readLog = " + readLog);
}
}
使用适配器模式来实现示例
第二版接口
package day03适配器模式;
import java.util.List;
/**
* 定义第二版的接口
*/
public interface LogDBDBApi {
/**
* 增
*/
public void createLog(LogModel lm);
/**
* 删
*/
public void removeLog(LogModel lm);
/**
* 查所有
*/
public List<LogModel> getAllLog();
}
新建一个适配器对象,实现第二版的接口,你要想实现第一版的接口,还需要持有这个第一版的接口对象,在适配器对象的有参构造里面将第一版的接口传进去。在方法里进行补充
package day03适配器模式;
import java.util.List;
public class Adapter implements LogDBDBApi{
//需要持有被适配的接口对象
private LogFileOperateApi adaptee;
public Adapter(LogFileOperateApi adaptee){
this.adaptee = adaptee;
}
/**
* 新增日志
* @param lm
*/
@Override
public void createLog(LogModel lm) {
// 这里不做第二版的实现,只做第一版怎么加入第二版里面
// 1.先读取文件的内容
List<LogModel> list = adaptee.readLogFile();
// 2.加入新的日志对象
list.add(lm);
// 3.重新写入文件
adaptee.writeLogFile(list);
}
@Override
public void removeLog(LogModel lm) {
// 这里不做第二版的实现,只做第一版怎么加入第二版里面
// 1.先读取文件的内容
List<LogModel> list = adaptee.readLogFile();
// 2.删除对应的日志对象
list.remove(lm);
// 3.重新写入文件
adaptee.writeLogFile(list);
}
@Override
public List<LogModel> getAllLog() {
return adaptee.readLogFile();
}
}
客户端
package day03适配器模式;
import java.util.ArrayList;
import java.util.List;
public class Client {
// public static void main(String[] args) {
// LogModel lml = new LogModel();
// lml.setLogId("001");
// lml.setOperateUser("admin");
// lml.setLogData("这是日志内容");
// List<LogModel> list = new ArrayList<>();
// list.add(lml);
// // 创建操作日志文件的对象
// LogFileOperateApi api = new LogFileOperateImpl("");
// // 保存日志文件
// api.writeLogFile(list);
//
// //读取日志文件的内容
// List<LogModel> readLog = api.readLogFile();
// System.out.println("readLog = " + readLog);
// }
public static void main(String[] args) {
LogModel lml = new LogModel();
lml.setLogId("002");
lml.setOperateUser("admin");
lml.setLogData("这是日志内容");
// 创建操作日志文件的对象 (第一版)
LogFileOperateApi logFileApi = new LogFileOperateImpl("");
// 创建新版操作日志的接口对象
Adapter adapter = new Adapter(logFileApi);
// 保存日志文件
adapter.createLog(lml);
//读取日志文件的内容
List<LogModel> allLog = adapter.getAllLog();
System.out.println("allLog = " + allLog);
}
}