適配器模式Adapter-日誌管理階段迭代案例-JAVA實現

=====開發第一階段
客戶第一階段需求:
* 用戶要求記錄數據庫操作日誌,存儲形式爲文件;
* 記錄信息有:日誌流水號、執行人員、執行操作內容(更新/刪除/插入等...)、執行時間;
開發分析:
* 定義日誌模型,對日誌對象進行序列化存文件。
* 實現日誌存儲方式
* 進行接口測試

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

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章