适配器模式的定义:
将一个类的接口转换成客户希望的另外一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
demo:下面使用双向适配器写一个简单的支持db和文件的log记录功能。
将要创建的类:
LogModel:日志数据对象
LogFileOperateApi:日志文件操作接口
LogDbOperateApi:数据库操作日志
LogFileOperateApiService:文件日志操作实现
LogDbOperateService:数据库日志操作实现
Client:服务端
/**
* 日志数据对象
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class LogModel implements Serializable {
private String logId;
private String operateUser;
private String operateTime;
private String logContent;
}
public interface LogFileOperateApi {
/**
* 读取日志文件
* @return
*/
List<LogModel> readLogFile();
/**
* 写日志文件
* @param list
*/
void writeLogFile(List<LogModel> list);
}
public interface LogDbOperateApi {
void createLog(LogModel logModel);
void updateLog(LogModel logModel);
void removeLog(LogModel logModel);
List<LogModel> findAllLog();
}
@Slf4j
public class LogFileOperateApiService implements LogFileOperateApi {
/**
* 日志文件路径及文件名
*/
private String logFilePathName = "AdapterLog.log";
public LogFileOperateApiService(String logFilePathName) {
if(StringUtils.isNotBlank(logFilePathName)){
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) {
log.error("readLogFile:Exception:", e);
} finally {
try {
if (oin != null) {
oin.close();
}
} catch (Exception e) {
log.error("readLogFile:finally Exception:", e);
}
}
return list;
}
@Override
public void writeLogFile(List<LogModel> list) {
File f = new File(logFilePathName);
ObjectOutputStream out = null;
try {
out = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(f)));
out.writeObject(list);
} catch (Exception e) {
log.error("writeLogFile:Exception:", e);
} finally {
try {
if (out != null) {
out.close();
}
} catch (Exception e) {
log.error("writeLogFile:finally Exception:", e);
}
}
}
}
@Slf4j
public class LogDbOperateService implements LogDbOperateApi{
@Override
public void createLog(LogModel logModel) {
log.info("createLog. logModel:{}", JSON.toJSONString(logModel));
}
@Override
public void updateLog(LogModel logModel) {
log.info("updateLog. logModel:{}", JSON.toJSONString(logModel));
}
@Override
public void removeLog(LogModel logModel) {
log.info("removeLog. logModel:{}", JSON.toJSONString(logModel));
}
@Override
public List<LogModel> findAllLog() {
log.info("findAllLog");
return null;
}
}
public class TwoDirectAdapter implements LogDbOperateApi,LogFileOperateApi{
private LogDbOperateApi logDbOperateApi;
private LogFileOperateApi logFileOperateApi;
public TwoDirectAdapter(LogDbOperateApi logDbOperateApi, LogFileOperateApi logFileOperateApi) {
this.logDbOperateApi = logDbOperateApi;
this.logFileOperateApi = logFileOperateApi;
}
@Override
public void createLog(LogModel logModel) {
List<LogModel> logModels = logFileOperateApi.readLogFile();
if(CollectionUtils.isEmpty(logModels)){
logModels = new ArrayList<>();
}
logModels.add(logModel);
logFileOperateApi.writeLogFile(logModels);
}
@Override
public void updateLog(LogModel logModel) {
List<LogModel> logModels = logFileOperateApi.readLogFile();
for (int i = 0; i < logModels.size(); i++) {
if(logModels.get(i).getLogId().equals(logModel.getLogId())){
logModels.set(i, logModel);
break;
}
}
logFileOperateApi.writeLogFile(logModels);
}
@Override
public void removeLog(LogModel logModel) {
List<LogModel> logModels = logFileOperateApi.readLogFile();
logModels.remove(logModel);
logFileOperateApi.writeLogFile(logModels);
}
@Override
public List<LogModel> findAllLog() {
return logFileOperateApi.readLogFile();
}
@Override
public List<LogModel> readLogFile() {
return logDbOperateApi.findAllLog();
}
@Override
public void writeLogFile(List<LogModel> list) {
for(LogModel lm : list){
logDbOperateApi.createLog(lm);
}
}
}
public class Client {
public static void main(String[] args) {
LogModel lml = LogModel.builder()
.logId("1")
.operateUser("test")
.operateTime(LocalDateTime.now().toString())
.logContent("测试")
.build();
List<LogModel> list = new ArrayList<>();
LogFileOperateApi logFileOperateApi = new LogFileOperateApiService("");
LogDbOperateApi logDbOperateApi = new LogDbOperateService();
LogFileOperateApi api = new TwoDirectAdapter(logDbOperateApi, logFileOperateApi);
LogDbOperateApi dbApi = new TwoDirectAdapter(logDbOperateApi, logFileOperateApi);
dbApi.createLog(lml);
List<LogModel> logModels = dbApi.findAllLog();
System.out.println(logModels);
api.writeLogFile(list);
api.readLogFile();
}
}
适配器模式的优点:
更好的复用性
更好的扩展性
适配器模式的缺点:
过多的使用适配器,会让系统非常凌乱,不容易整体进行把握
何时选用适配器模式:
如果想要使用一个已经存在的类,但是它的接口不符合你的需求,可以使用适配器模式把已有的实现转换成你需要的接口。
如果你想创建一个可以复用的类,这个类可行和一些不兼容的类一起工作,这种情况可以使用适配器模式。
如果你想使用一些已经存在的子类,但是不可能对每一个子类都进行适配,这种情况可以选用对象适配器,直接适配这些子类的父类就可以了。