适配器模式(Adapter)
@@@模式定义:
将一个类的接口转换成客户希望的另外一个接口。
适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
@@@练习示例:
日志管理
@@@第一版代码:
log\LogModel.java [日志数据Model]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
package log;
import java.io.Serializable;
/**
* 日志数据对象
*/
public class LogModel implements Serializable {
/**
* serialVersionUID
*/
private static final long serialVersionUID = 1L;
/**
* 日志编号
*/
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 + ", oprateUser=" + operateUser
+ ", operateTime=" + operateTime + ", logContent=" + logContent;
}
}
log\LogFileOperateApi.java [使用文件处理日志的接口]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
package log;
import java.util.List;
/**
* 日志文件操作接口
*/
public interface LogFileOperateApi {
/**
* 读取日志文件,从文件里面获取存储的日志列表对象
* @return 存储的日志列表对象
*/
public List<LogModel> readLogFile();
/**
* 写日志文件,把日志列表写到日志文件中去
* @param list 要写到日志文件中的日志列表
*/
public void writeLogFile(List<LogModel> list);
}
log\LogFileOperate.java [使用文件处理日志的实现]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
忽略
user\Client.java [用户程序示例]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
package user;
import java.util.ArrayList;
import java.util.List;
import log.LogFileOperate;
import log.LogFileOperateApi;
import log.LogModel;
public class Client {
public static void main(String[] args) {
// 准备日志内容,也就是测试的数据
LogModel lml = new LogModel();
lml.setLogId("001");
lml.setOperateUser("admin");
lml.setOperateTime("2013-05-11 11:27:55");
lml.setLogContent("这是一个测试");
List<LogModel> list = new ArrayList<LogModel>();
list.add(lml);
// 创建操作日志文件的对象
LogFileOperateApi api = new LogFileOperate("");
// 保存日志文件
api.writeLogFile(list);
// 读取日志文件的内容
List<LogModel> readLog = api.readLogFile();
System.out.println("readLog=" + readLog);
}
}
@@@需求变更:
需要使用数据库处理日志,同时保留原有使用文件处理日志的功能。
@@@第二版代码:
log\LogDbOperateApi.java [使用数据库处理日志的接口]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
package log;
import java.util.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();
}
@@@存在问题:
当前有了文件管理日志的接口和实现,数据库管理日志的接口和实现(忽略),
需要在新的版本中同时支持文件和数据库管理日志,但是文件管理日志的接口和数据库管理日志的接口不同。
当前使用第二版的接口,客户端无法以同样的方式来直接使用第一版的实现,
即无法在客户端使用数据库管理日志的接口来直接使用文件管理日志的实现。
出现了接口不兼容的问题。
如果直接修改第一版的代码,那么可能会导致其他依赖于这些实现的应用不能正常运行。
再说,有可能第一版和第二版是不同团队开发的,在第二版实现的时候,根本拿不到第一版的源代码。
@@@使用模式:
新增一个适配器,新瓶装老酒。
log\Adapter.java [适配器]
~~~~~~~~~~~~~~~~~~~~~~~~~
package log;
import java.util.ArrayList;
import java.util.List;
/**
* 适配器对象,将记录日志到文件的功能适配成第二版需要的增删改查功能
*/
public class Adapter implements LogDbOperateApi {
/**
* 持有需要配适配的接口对象
*/
private LogFileOperateApi adaptee;
/**
* 构造方法,传入需要被适配的对象
*/
public Adapter(LogFileOperateApi adaptee) {
this.adaptee = adaptee;
}
public void createLog(LogModel lm) {
// 1: 先读取文件的内容
List<LogModel> list = adaptee.readLogFile();
// 2: 已经存在时直接退出
if (null != list) {
for (int i = 0; i < list.size(); i++) {
if (list.get(i).getLogId().equals(lm.getLogId())) {
return;
}
}
}
// 3: 加入新的日志对象
if (null == list) {
list = new ArrayList<LogModel>();
}
list.add(lm);
// 4: 重新写入文件
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);
}
}
user\Client.java [用户程序示例]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
package user;
import java.util.List;
import log.Adapter;
import log.LogDbOperateApi;
import log.LogFileOperate;
import log.LogFileOperateApi;
import log.LogModel;
public class Client {
public static void main(String[] args) {
// 准备日志内容,也就是测试的数据
LogModel lml = new LogModel();
lml.setLogId("001");
lml.setOperateUser("admin");
lml.setOperateTime("2013-05-11 11:27:55");
lml.setLogContent("这是一个测试");
// 创建操作日志文件的对象
LogFileOperateApi logFileApi = new LogFileOperate("");
// 创建新版操作日志的接口对象
LogDbOperateApi logDbApi = new Adapter(logFileApi);
// 保存日志文件
logDbApi.createLog(lml);
// 读取日志文件的内容
List<LogModel> allLog = logDbApi.getAllLog();
System.out.println("allLog=" + allLog);
}
}
此时,就可以用第二版的接口这个新瓶子来装第一版实现这个老酒了。
@@@适配器模式的实现:
1. 适配器通常实现成一个实现Target接口的类;
2. 适配器也可以实现一些Adaptee没有实现,但是在Target中定义的功能;
3. 一个适配器可以适配多个Adaptee;
4. 缺省适配器可用来为一个接口提供默认实现;
5. 双向适配器可以同时当作Target和Adaptee来使用;
6. 对象适配器的实现依赖于对象组合;
7. 类适配器的实现采用多重继承对一个接口与另一个接口进行匹配;
@@@适配器模式的优点:
1. 更好的复用性;
2. 更好的可扩展性;
@@@适配器模式的缺点:
1. 过多地使用适配器,会使系统非常凌乱,不容易进行整体把握;
@@@适配器模式的本质:
转换匹配(手段),复用功能(目的);
@@@适配器模式体现的设计原则:
@@@模式定义:
将一个类的接口转换成客户希望的另外一个接口。
适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
@@@练习示例:
日志管理
@@@第一版代码:
log\LogModel.java [日志数据Model]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
package log;
import java.io.Serializable;
/**
* 日志数据对象
*/
public class LogModel implements Serializable {
/**
* serialVersionUID
*/
private static final long serialVersionUID = 1L;
/**
* 日志编号
*/
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 + ", oprateUser=" + operateUser
+ ", operateTime=" + operateTime + ", logContent=" + logContent;
}
}
log\LogFileOperateApi.java [使用文件处理日志的接口]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
package log;
import java.util.List;
/**
* 日志文件操作接口
*/
public interface LogFileOperateApi {
/**
* 读取日志文件,从文件里面获取存储的日志列表对象
* @return 存储的日志列表对象
*/
public List<LogModel> readLogFile();
/**
* 写日志文件,把日志列表写到日志文件中去
* @param list 要写到日志文件中的日志列表
*/
public void writeLogFile(List<LogModel> list);
}
log\LogFileOperate.java [使用文件处理日志的实现]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
忽略
user\Client.java [用户程序示例]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
package user;
import java.util.ArrayList;
import java.util.List;
import log.LogFileOperate;
import log.LogFileOperateApi;
import log.LogModel;
public class Client {
public static void main(String[] args) {
// 准备日志内容,也就是测试的数据
LogModel lml = new LogModel();
lml.setLogId("001");
lml.setOperateUser("admin");
lml.setOperateTime("2013-05-11 11:27:55");
lml.setLogContent("这是一个测试");
List<LogModel> list = new ArrayList<LogModel>();
list.add(lml);
// 创建操作日志文件的对象
LogFileOperateApi api = new LogFileOperate("");
// 保存日志文件
api.writeLogFile(list);
// 读取日志文件的内容
List<LogModel> readLog = api.readLogFile();
System.out.println("readLog=" + readLog);
}
}
@@@需求变更:
需要使用数据库处理日志,同时保留原有使用文件处理日志的功能。
@@@第二版代码:
log\LogDbOperateApi.java [使用数据库处理日志的接口]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
package log;
import java.util.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();
}
@@@存在问题:
当前有了文件管理日志的接口和实现,数据库管理日志的接口和实现(忽略),
需要在新的版本中同时支持文件和数据库管理日志,但是文件管理日志的接口和数据库管理日志的接口不同。
当前使用第二版的接口,客户端无法以同样的方式来直接使用第一版的实现,
即无法在客户端使用数据库管理日志的接口来直接使用文件管理日志的实现。
出现了接口不兼容的问题。
如果直接修改第一版的代码,那么可能会导致其他依赖于这些实现的应用不能正常运行。
再说,有可能第一版和第二版是不同团队开发的,在第二版实现的时候,根本拿不到第一版的源代码。
@@@使用模式:
新增一个适配器,新瓶装老酒。
log\Adapter.java [适配器]
~~~~~~~~~~~~~~~~~~~~~~~~~
package log;
import java.util.ArrayList;
import java.util.List;
/**
* 适配器对象,将记录日志到文件的功能适配成第二版需要的增删改查功能
*/
public class Adapter implements LogDbOperateApi {
/**
* 持有需要配适配的接口对象
*/
private LogFileOperateApi adaptee;
/**
* 构造方法,传入需要被适配的对象
*/
public Adapter(LogFileOperateApi adaptee) {
this.adaptee = adaptee;
}
public void createLog(LogModel lm) {
// 1: 先读取文件的内容
List<LogModel> list = adaptee.readLogFile();
// 2: 已经存在时直接退出
if (null != list) {
for (int i = 0; i < list.size(); i++) {
if (list.get(i).getLogId().equals(lm.getLogId())) {
return;
}
}
}
// 3: 加入新的日志对象
if (null == list) {
list = new ArrayList<LogModel>();
}
list.add(lm);
// 4: 重新写入文件
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);
}
}
user\Client.java [用户程序示例]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
package user;
import java.util.List;
import log.Adapter;
import log.LogDbOperateApi;
import log.LogFileOperate;
import log.LogFileOperateApi;
import log.LogModel;
public class Client {
public static void main(String[] args) {
// 准备日志内容,也就是测试的数据
LogModel lml = new LogModel();
lml.setLogId("001");
lml.setOperateUser("admin");
lml.setOperateTime("2013-05-11 11:27:55");
lml.setLogContent("这是一个测试");
// 创建操作日志文件的对象
LogFileOperateApi logFileApi = new LogFileOperate("");
// 创建新版操作日志的接口对象
LogDbOperateApi logDbApi = new Adapter(logFileApi);
// 保存日志文件
logDbApi.createLog(lml);
// 读取日志文件的内容
List<LogModel> allLog = logDbApi.getAllLog();
System.out.println("allLog=" + allLog);
}
}
此时,就可以用第二版的接口这个新瓶子来装第一版实现这个老酒了。
@@@适配器模式的实现:
1. 适配器通常实现成一个实现Target接口的类;
2. 适配器也可以实现一些Adaptee没有实现,但是在Target中定义的功能;
3. 一个适配器可以适配多个Adaptee;
4. 缺省适配器可用来为一个接口提供默认实现;
5. 双向适配器可以同时当作Target和Adaptee来使用;
6. 对象适配器的实现依赖于对象组合;
7. 类适配器的实现采用多重继承对一个接口与另一个接口进行匹配;
@@@适配器模式的优点:
1. 更好的复用性;
2. 更好的可扩展性;
@@@适配器模式的缺点:
1. 过多地使用适配器,会使系统非常凌乱,不容易进行整体把握;
@@@适配器模式的本质:
转换匹配(手段),复用功能(目的);
@@@适配器模式体现的设计原则:
OCP(开闭原则),对扩展开放,对修改关闭;
@@@代码链接:
http://download.youkuaiyun.com/detail/jinfengmusic/5385221