天天看点

适配器模式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版)》、《设计模式可复用面向对象软件的基础》《设计模式可复用面向对象软件的基础》,参考其中源码,用于学习记录。