=====開發第一階段
客戶第一階段需求:
* 用戶要求記錄數據庫操作日誌,存儲形式爲文件;
* 記錄信息有:日誌流水號、執行人員、執行操作內容(更新/刪除/插入等...)、執行時間;
開發分析:
* 定義日誌模型,對日誌對象進行序列化存文件。
* 實現日誌存儲方式
* 進行接口測試
UML設計圖:
源碼:
Client.java
package com.pattern.adapterlogmanger1;
import java.util.List;
import java.util.ArrayList;
/**
* 客戶端
* @author yuanwm
*
*/
public class Client {
public static void main(String[] args) {
//定義測試數據
LogManage log = new LogManage();
log.setLogSerialNo("001");
log.setLogOperaUser("yuanwm");
log.setLogOperaType("update");
log.setLogOperaTime("2018-12-24 09:00:00");
log.setLogOperaContent("更新一個表");
List<LogManage> list = new ArrayList<LogManage>();
list.add(log);
//實例化日誌操作對象
LogOpera logApi = new LogOpera("./log.txt");
//寫日誌
logApi.WriteLogFile(list);
//讀取日誌文件內容
List<LogManage> readList = logApi.readLogFile();
System.out.println("log="+readList);
}
}
LogManage.java
package com.pattern.adapterlogmanger1;
import java.io.Serializable;
/**
* 日誌管理對象
* @author yuanwm
*/
public class LogManage implements Serializable {
/**
*實現 Serializable這個接口才能進行序列化。
*/
//一個設爲固定的 1L,另一個是隨機生成一個不重複的 long 類型數據(實際上是使用 JDK 工具生成)。
//一般如果沒有特殊需求,用默認的 1L 就可以,這樣可以確保反序列化成功。因爲不同的序列化id之間不能進行序列化和反序列化。
private static final long serialVersionUID = 1L;
private String logSerialNo; //日誌流水號
private String logOperaUser; //執行人員
private String logOperaType; //執行操作類型(更新/刪除/插入等...)
private String logOperaContent; //執行操作內容
private String logOperaTime; //執行時間
public String getLogSerialNo() {
return logSerialNo;
}
public void setLogSerialNo(String logSerialNo) {
this.logSerialNo = logSerialNo;
}
public String getLogOperaUser() {
return logOperaUser;
}
public void setLogOperaUser(String logOperaUser) {
this.logOperaUser = logOperaUser;
}
public String getLogOperaType() {
return logOperaType;
}
public void setLogOperaType(String logOperaType) {
this.logOperaType = logOperaType;
}
public String getLogOperaContent() {
return logOperaContent;
}
public void setLogOperaContent(String logOperaContent) {
this.logOperaContent = logOperaContent;
}
public String getLogOperaTime() {
return logOperaTime;
}
public void setLogOperaTime(String logOperaTime) {
this.logOperaTime = logOperaTime;
}
public String toString(){
return "logSerialNo="+logSerialNo+",logOperaUser="+logOperaUser+",logOperaType="+logOperaType+","
+ "logOperaContent="+logOperaContent+ "," + "logOperaTime=" + logOperaTime;
}
}
LogOpera.java
package com.pattern.adapterlogmanger1;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.List;
/**
* 實現日誌操作
* @author yuanwm
*
*/
public class LogOpera implements LogOperaApi {
private String logFilePathName = null;
public LogOpera(String inlogFilePathName ) {
// TODO Auto-generated constructor stub
if(inlogFilePathName !=null && inlogFilePathName.trim().length() > 0) {
this.logFilePathName = inlogFilePathName;
}
}
@Override
public List<LogManage> readLogFile() {
// TODO Auto-generated method stub
List<LogManage> listManage = null;
ObjectInputStream ioInputStream = null;
try {
File fpFile = new File(logFilePathName);
if(fpFile.exists()){
ioInputStream = new ObjectInputStream(
new BufferedInputStream( new FileInputStream(fpFile)
));
listManage = (List <LogManage>)ioInputStream.readObject();
}
}catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}finally {
try {
if(ioInputStream != null) {
ioInputStream.close();
}
}catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
return listManage;
}
@Override
public void WriteLogFile(List<LogManage> list) {
// TODO Auto-generated method stub
File fpFile = new File(logFilePathName);
ObjectOutputStream ioOutputStream = null;
try {
ioOutputStream = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(fpFile)));
ioOutputStream.writeObject(list);
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}finally {
try {
if (ioOutputStream != null) {
ioOutputStream.close();
}
}catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
}
}
LogOperaApi.java
package com.pattern.adapterlogmanger1;
import java.util.List;
/**
* 日誌操作的接口定義
* @author yuanwm
*
*/
public interface LogOperaApi {
/**
* 讀取日誌文件,從文件裏獲取日誌存儲的對象
* @return 存儲日誌的對象
*/
public List<LogManage> readLogFile();
/**
* 寫日誌文件,將日誌對象寫到文件中
* @param list 要寫到日誌文件的對象
*/
public void WriteLogFile(List<LogManage> list);
}
=====開發第二階段
客戶第二階段需求:
* 客戶要求增加日誌存入數據庫的功能,與原功能並用
開發分析:
* 定義數據庫存儲的接口
* 原客戶端可以不變,新客戶端就需要選擇使用兩個功能。
* 定義一個適配器,同時支持文件與數據庫的操作。使用對象適配器。
UML:
增改源碼:
Client.java
package com.pattern.adapterlogmanger2;
import java.util.List;
import java.util.ArrayList;
/**
* 客戶端
*
* @author yuanwm
*
*/
public class Client {
public static void main(String[] args) {
// 定義測試數據
LogManage log = new LogManage();
log.setLogSerialNo("001");
log.setLogOperaUser("yuanwm");
log.setLogOperaType("update");
log.setLogOperaTime("2018-12-24 09:00:00");
log.setLogOperaContent("更新一個表");
List<LogManage> list = new ArrayList<LogManage>();
list.add(log);
// 實例化文件日誌操作對象
LogOpera logApi = new LogOpera("./log.txt");
// 進行添加進最最新的適配
LogAdapter Adapter = new LogAdapter(logApi);
/**
* 原文件操作方式
*/
// 寫日誌
Adapter.WriteLogFile(list);
// 讀取日誌文件內容
List<LogManage> readList = Adapter.readLogFile();
System.out.println("log=" + readList);
/**
* 目前數據庫的操作方式
*/
// 插入
Adapter.insertDbOpera(list);
// 更新
Adapter.updateDbOpera(list);
// 刪除
Adapter.removeDbOpera(list);
// 查詢
Adapter.queryDblog();
}
}
LogAdapter.java
package com.pattern.adapterlogmanger2;
import java.util.List;
/**
* 這是適配器的實現;
* 對於數據庫操作jdb等過程暫不實現,這裏主要注重模式的應用解決問題。
* @author yuanwm
*
*/
public class LogAdapter implements LogDbOperaApi {
private LogOpera logFileAdaptee;
public LogAdapter(LogOpera logFileAdaptee) {
this.logFileAdaptee = logFileAdaptee;
}
public List<LogManage> readLogFile() {
return logFileAdaptee.readLogFile();
}
public void WriteLogFile(List<LogManage> list) {
logFileAdaptee.WriteLogFile(list);
}
@Override
public void insertDbOpera(List<LogManage> loglist) {
// TODO Auto-generated method stub
System.out.println("以下日誌已經插入數據庫");
System.out.println("log:" + loglist);
}
@Override
public void updateDbOpera(List<LogManage> loglist) {
// TODO Auto-generated method stub
System.out.println("以下日誌已經更新數據庫");
System.out.println("log:" + loglist);
}
@Override
public void removeDbOpera(List<LogManage> loglist) {
// TODO Auto-generated method stub
System.out.println("以下日誌已經從數據庫刪除");
System.out.println("log:" + loglist);
}
@Override
public List<LogManage> queryDblog() {
// TODO Auto-generated method stub
System.out.println("[測試]已經完成數據庫數據查詢");
return null;
}
}
LogDbOperaApi.java
package com.pattern.adapterlogmanger2;
import java.util.List;
/**
* 日誌數據庫操作API 新增,更新,刪除,查詢操作
*
* @author yuanwm
*
*/
public interface LogDbOperaApi {
/**
* 新增
*/
public void insertDbOpera(List<LogManage> loglist);
/**
* 更新
*/
public void updateDbOpera(List<LogManage> loglist);
/**
* 刪除
*/
public void removeDbOpera(List<LogManage> loglist);
/**
* 查詢所有日誌
*/
public List<LogManage> queryDblog();
}
=====開發第三階段
客戶第三階段需求:
* 客戶要求第一版與第二版共存,但是主要還是使用第一版。意思是用第一版的接口,第一版的界面,
但是,實際操作的是第二版的DB。第二版也能操作第一版的方式。
* 在本實例中即:文件方式實際操作DB,DB方式實際操作文件。原第一版接口直接操作的DB。
開發分析:
* 定義數據庫操作與接口
* 通過實現數據庫、文件兩個接口,達到一個雙向適配器,即:文件-》數據庫,數據庫-》文件。
UML:
增改源碼:
Client.java
package com.pattern.adapterlogmanger3;
import java.util.List;
import java.util.ArrayList;
/**
* 客戶端
*
* @author yuanwm
*
*/
public class Client {
public static void main(String[] args) {
// 定義測試數據
LogManage log = new LogManage();
log.setLogSerialNo("001");
log.setLogOperaUser("yuanwm");
log.setLogOperaType("update");
log.setLogOperaTime("2018-12-24 09:00:00");
log.setLogOperaContent("更新一個表");
List<LogManage> list = new ArrayList<LogManage>();
list.add(log);
// 實例化文件日誌操作對象
LogOperaApi logApi = new LogOpera("./log.txt");
// 實例化數據庫操作對象
LogDbOperaApi dbApi = new LogDbOpera();
// 進行添加進最最新的適配
LogBothwayAdapter Adapter = new LogBothwayAdapter(logApi, dbApi);
/**
* 數據庫是配到文件。
*/
// 寫日誌
Adapter.WriteLogFile(list);
// 讀取日誌文件內容,這裏沒有實現數據庫過程,因此暫時不輸出
Adapter.readLogFile();
/**
* 文件適配到數據庫
*/
// 插入
Adapter.insertDbOpera(list);
System.out.println("插入後:log=" + Adapter.queryDblog());
// 更新
Adapter.updateDbOpera(list);
System.out.println("更新後:log=" + Adapter.queryDblog());
// 刪除
Adapter.removeDbOpera(list);
System.out.println("刪除後:log=" + Adapter.queryDblog());
}
}
LogDbOpera.java
package com.pattern.adapterlogmanger3;
/**
* 對logdb操作的簡單實現
* 具體操作數據庫的方式暫不實現,注重模式的應用解決問題
*/
import java.util.List;
public class LogDbOpera implements LogDbOperaApi {
@Override
public void insertDbOpera(List<LogManage> loglist) {
// TODO Auto-generated method stub
System.out.println("以下日誌已經插入數據庫");
System.out.println("log:" + loglist);
}
@Override
public void updateDbOpera(List<LogManage> loglist) {
// TODO Auto-generated method stub
System.out.println("以下日誌已經更新數據庫");
System.out.println("log:" + loglist);
}
@Override
public void removeDbOpera(List<LogManage> loglist) {
// TODO Auto-generated method stub
System.out.println("以下日誌已經從數據庫刪除");
System.out.println("log:" + loglist);
}
@Override
public List<LogManage> queryDblog() {
// TODO Auto-generated method stub
System.out.println("[測試]已經完成數據庫數據查詢");
return null;
}
}
BothwayAdapter.java
package com.pattern.adapterlogmanger3;
import java.util.List;
/**
* 這是雙向適配器的實現; 對於數據庫操作jdb等過程暫不實現,這裏主要注重模式的應用解決問題。 將Db操作實現爲文件的方式,將file操作實現爲db的方式;
* 調用db的方法實際是文件操作,調用文件的方法實際是db的操作 暫時選擇與原實現方法名一致,如果不一致也不影響。
*
* @author yuanwm
*
*/
public class LogBothwayAdapter implements LogDbOperaApi, LogOperaApi {
private LogOperaApi logFileAdaptee;
private LogDbOperaApi logDbAdaptee;
public LogBothwayAdapter(LogOperaApi logFileAdaptee, LogDbOperaApi logDbAdaptee) {
this.logFileAdaptee = logFileAdaptee;
this.logDbAdaptee = logDbAdaptee;
}
/**
* db實現到文件的方法中
*/
public List<LogManage> readLogFile() {
return logDbAdaptee.queryDblog();
}
public void WriteLogFile(List<LogManage> list) {
logDbAdaptee.insertDbOpera(list);
}
/**
* file實現到Db的方法中
*/
@Override
public void insertDbOpera(List<LogManage> loglist) {
// TODO Auto-generated method stub
logFileAdaptee.WriteLogFile(loglist);
}
@Override
public void updateDbOpera(List<LogManage> loglist) {
// TODO Auto-generated method stub
List<LogManage> list = logFileAdaptee.readLogFile();
for (int i = 0; i < loglist.size(); i++) {
for (int j = 0; j < list.size(); j++) {
if (list.get(j).getLogSerialNo().equals(loglist.get(i).getLogSerialNo())) {
list.set(j, loglist.get(i));
break;
}
}
}
}
@Override
public void removeDbOpera(List<LogManage> loglist) {
// TODO Auto-generated method stub
List<LogManage> list = logFileAdaptee.readLogFile();
for (LogManage tmplog : loglist) {
for (int j = 0; j < list.size(); j++) {
if (list.get(j).getLogSerialNo().equals(tmplog.getLogSerialNo())) {
list.remove(j);
logFileAdaptee.WriteLogFile(list);
break;
}
}
}
}
@Override
public List<LogManage> queryDblog() {
// TODO Auto-generated method stub
return logFileAdaptee.readLogFile();
}
}
=====開發第四階段(類適配器,與第二階段需求一致)
UML設計:
增改源碼,其他同第二階段源碼:
Client.java
package com.pattern.adapterlogmanger4;
import java.util.List;
import java.util.ArrayList;
/**
* 客戶端
*
* @author yuanwm
*
*/
public class Client {
public static void main(String[] args) {
// 定義測試數據
LogManage log = new LogManage();
log.setLogSerialNo("001");
log.setLogOperaUser("yuanwm");
log.setLogOperaType("update");
log.setLogOperaTime("2018-12-24 09:00:00");
log.setLogOperaContent("更新一個表");
List<LogManage> list = new ArrayList<LogManage>();
list.add(log);
// 進行添加進最最新的適配
LogClassAdapter Adapter = new LogClassAdapter("./log.txt");
/**
* 原文件操作方式
*/
// 寫日誌
Adapter.WriteLogFile(list);
// 讀取日誌文件內容
List<LogManage> readList = Adapter.readLogFile();
System.out.println("log=" + readList);
/**
* 目前數據庫的操作方式
*/
// 插入
Adapter.insertDbOpera(list);
// 更新
Adapter.updateDbOpera(list);
// 刪除
Adapter.removeDbOpera(list);
// 查詢
Adapter.queryDblog();
}
}
LogClassAdapter.java
package com.pattern.adapterlogmanger4;
import java.util.List;
/**
* 這是類適配器的實現;
* 對於數據庫操作jdb等過程暫不實現,這裏主要注重模式的應用解決問題。
* 由於是繼承,且參數模板一致,因此可以直接調用。
* @author yuanwm
*
*/
public class LogClassAdapter extends LogOpera implements LogDbOperaApi {
public LogClassAdapter(String logPathName) {
super(logPathName);
}
@Override
public void insertDbOpera(List<LogManage> loglist) {
// TODO Auto-generated method stub
System.out.println("以下日誌已經插入數據庫");
System.out.println("log:" + loglist);
}
@Override
public void updateDbOpera(List<LogManage> loglist) {
// TODO Auto-generated method stub
System.out.println("以下日誌已經更新數據庫");
System.out.println("log:" + loglist);
}
@Override
public void removeDbOpera(List<LogManage> loglist) {
// TODO Auto-generated method stub
System.out.println("以下日誌已經從數據庫刪除");
System.out.println("log:" + loglist);
}
@Override
public List<LogManage> queryDblog() {
// TODO Auto-generated method stub
System.out.println("[測試]已經完成數據庫數據查詢");
return null;
}
}
參考書籍:《Java設計模式(第2版)》、《設計模式可複用面向對象軟件的基礎》《設計模式可複用面向對象軟件的基礎》,參考其中源碼,用於學習記錄。