天天看點

擴充卡模式Adapter-日志管理階段疊代案例-JAVA實作

=====開發第一階段

客戶第一階段需求:

* 使用者要求記錄資料庫記錄檔,存儲形式為檔案;

* 記錄資訊有:日志流水号、執行人員、執行操作内容(更新/删除/插入等...)、執行時間;

開發分析:

* 定義日志模型,對日志對象進行序列化存檔案。

* 實作日志存儲方式

* 進行接口測試

UML設計圖:

擴充卡模式Adapter-日志管理階段疊代案例-JAVA實作

源碼:

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:

擴充卡模式Adapter-日志管理階段疊代案例-JAVA實作

增改源碼:

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:

擴充卡模式Adapter-日志管理階段疊代案例-JAVA實作

增改源碼:

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設計:

擴充卡模式Adapter-日志管理階段疊代案例-JAVA實作

增改源碼,其他同第二階段源碼:

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版)》、《設計模式可複用面向對象軟體的基礎》《設計模式可複用面向對象軟體的基礎》,參考其中源碼,用于學習記錄。