=====開發第一階段
客戶第一階段需求:
* 使用者要求記錄資料庫記錄檔,存儲形式為檔案;
* 記錄資訊有:日志流水号、執行人員、執行操作内容(更新/删除/插入等...)、執行時間;
開發分析:
* 定義日志模型,對日志對象進行序列化存檔案。
* 實作日志存儲方式
* 進行接口測試
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版)》、《設計模式可複用面向對象軟體的基礎》《設計模式可複用面向對象軟體的基礎》,參考其中源碼,用于學習記錄。