定义:
将一个类的接口转换成客户希望的另一个接口。适配器模式使原本由于接口不兼容不能在一个工作的类可以在一起工作。
Client:客户端,调用自己需要的目的接口Target。
Target:定义客户端需要的跟特定领域相关的接口。
Adaptee:已经存在的接口,但与客户端要求的特定领域接口不一致,选哟被适配。
Adapter:适配器,把Adaptee适配成为Client需要的Target
比如有一个日志管理的功能,第一版我们使用的是文件存储,相关类如下。
日志类:
/**
* 日志类
* @author w_zhanggs
*
*/
public class LogModel implements Serializable{
private String logid;
private String operatorUser;
private String operatorTime;
private String logContent;
public String getLogid() {
return logid;
}
public void setLogid(String logid) {
this.logid = logid;
}
public String getOperatorUser() {
return operatorUser;
}
public void setOperatorUser(String operatorUser) {
this.operatorUser = operatorUser;
}
public String getOperatorTime() {
return operatorTime;
}
public void setOperatorTime(String operatorTime) {
this.operatorTime = operatorTime;
}
public String getLogContent() {
return logContent;
}
public void setLogContent(String logContent) {
this.logContent = logContent;
}
@Override
public String toString() {
return "LogModel [logid=" + logid + ", operatorUser=" + operatorUser + ", operatorTime=" + operatorTime
+ ", logContent=" + logContent + "]";
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
LogModel other = (LogModel) obj;
if (logid == null) {
if (other.logid != null)
return false;
} else if (!logid.equals(other.logid))
return false;
return true;
}
}
日志操作接口:
public interface LogFileApi {
/**
* 从文件读取日志文件
* @return
*/
List<LogModel> readLogFile();
/**
* 将日志列表写入到日志文件中
* @param logModels
*/
void writeLogFile(List<LogModel> logModels);
}
日志操作实现类:
/**
* 日志操作实现类
* @author w_zhanggs
*
*/
public class LogFileOperate implements LogFileApi {
private String logFilePathName = "D:\\adaptee.log";
public LogFileOperate(String logFilePathName) {
if(logFilePathName!=null && logFilePathName.trim().length() > 0) {
this.logFilePathName = logFilePathName;
}
}
public LogFileOperate() {}
@Override
public List<LogModel> readLogFile() {
List<LogModel> logModels = new ArrayList<>() ;
File file = new File(logFilePathName);
ObjectInputStream oin = null ;
try {
if(!file.exists()) {
file.createNewFile();
}else {
oin = new ObjectInputStream(new BufferedInputStream(new FileInputStream(file)));
logModels = (List<LogModel>) oin.readObject();
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
if(oin != null) {
try {
oin.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
return logModels;
}
@Override
public void writeLogFile(List<LogModel> logModels) {
File file = new File(logFilePathName);
ObjectOutputStream oout = null;
try {
oout = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(file)));
oout.writeObject(logModels);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
if(oout != null) {
try {
oout.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
客户端:
public class Client {
public static void main(String[] args) {
List<LogModel> logModels = new ArrayList<>();
LogModel logModel = new LogModel();
logModel.setLogid("1");
logModel.setOperatorUser("张三");
logModel.setLogContent("适配器模式测试");
logModel.setOperatorTime("2018-10-31");
logModels.add(logModel);
/**
* 此处可以使用简单工厂模式,创建一个logFileFactory类,在logFileFactory中获得logFileApi接口的实现,
* 只将logFileFactory类暴露给客户端
*/
LogFileApi logFileApi = new LogFileOperate();
logFileApi.writeLogFile(logModels);
System.out.println("readlog:"+logFileApi.readLogFile());
}
}
由于业务变化,日志功能需要升级到第二版本,将数据保存到数据库中。
新版日志操作接口:
/**
* 数据库操作日志接口
* @author w_zhanggs
*
*/
public interface LogDbApi {
void createLog(LogModel logModel);
void updateLog(LogModel logModel);
void removeLog(LogModel logModel);
List<LogModel> getAllLogs();
}
新版接口的实现类此处略去,主要探讨实现适配器的应用。在升级后客户端开始使用LogDbApi 接口,经过一段时间后,有时也需要将日志写到文件中,我们需要在新接口LogDbApi 中复用第一版中的LogFileOperate 类,但由于接口不兼容无法复用,此时可以使用适配器模式。
适配器类:
/**
* 适配器对象
*
*/
public class Adapter implements LogDbApi {
/**
* 需要被适配的对象
*/
private LogFileApi adaptee;
public Adapter(LogFileApi adaptee) {
this.adaptee = adaptee;
}
@Override
public void createLog(LogModel logModel) {
List<LogModel> logModels = adaptee.readLogFile();
logModels.add(logModel);
adaptee.writeLogFile(logModels);
}
@Override
public void updateLog(LogModel logModel) {
if(logModel == null) return;
List<LogModel> logModels = adaptee.readLogFile();
for(LogModel logModel2:logModels) {
if(logModel.equals(logModel2)) {
logModels.remove(logModel2);
logModels.add(logModel);
}
}
adaptee.writeLogFile(logModels);
}
@Override
public void removeLog(LogModel logModel) {
List<LogModel> logModels = adaptee.readLogFile();
logModels.remove(logModel);
adaptee.writeLogFile(logModels);
}
@Override
public List<LogModel> getAllLogs() {
List<LogModel> logModels = adaptee.readLogFile();
return logModels;
}
}
Client类:
public class Client {
public static void main(String[] args) {
LogModel logModel = new LogModel();
logModel.setLogid("1");
logModel.setOperatorUser("张三");
logModel.setLogContent("适配器模式测试");
logModel.setOperatorTime("2018-10-31");
LogModel logModel2 = new LogModel();
logModel2.setLogid("2");
logModel2.setOperatorUser("李四");
logModel2.setLogContent("再测试");
logModel2.setOperatorTime("2018-11-31");
//新增日志
LogDbApi logDbApi = new Adapter(new LogFileOperate());
logDbApi.createLog(logModel);
logDbApi.createLog(logModel2);
System.out.println("readlog:"+logDbApi.getAllLogs());
//删除日志
logDbApi.removeLog(logModel2);
System.out.println("readlog:"+logDbApi.getAllLogs());
//修改日志
logModel.setLogContent("再再测试修改");
logDbApi.updateLog(logModel);
System.out.println("readlog:"+logDbApi.getAllLogs());
}
}
小结:
1.适配器模式的功能:进行转换匹配,目的是复用已有的功能,而不是实现新的接口
2.Adaptee和Target的关系:被适配的接口Adaptee和适配的目的接口Target没有关系
3.实现方式:依靠对象组合的方式(java是单继承,对于继承,优先使用组合),适配器是一个类,适配器类实现Target接口,让后在适配器类中调用Adaptee,Atapter实现的复杂程度取决去Target和Adaptee的相似程度
何使选用:
1.想用一个存在的类,但它的接口不符合你的要求,可以使用适配器,把已有的实现转换成你需要的接口
2.如果存在一些子类,不可能对每一个子类进行适配,可以选择对象适配器,对其父类进行适配。