日期:2014-05-16  浏览次数:20644 次

由数据库连接所联想到的5种设计模式
     最近在看设计模式方面的资料.突发灵感,从数据库的连接中联想到了5种设计模式.然后编写了下,都能实现,可能有些实现方式在实际生产环境中并没有意义.就当是对设计模式的学习吧.
     首先上演的就是策略模式.我们在连接数据库时,并非一种数据库,比如,有时是MySql,有时是Oracle,有时又换到SQL Server,都要涉及数据库的切换.此时.我们就可以将数据库连接的算法封装起来,使它们可以相互替换.
     首先我们定义一个策略接口,用来表示数据库的连接.
package strategy;

public interface Strategy {

	public void getConnDB();

}

     然后我们实现了对具体的策略类:三大数据库的连接.我们在这里只是强调模式的实现,简单起见,不实现JDBC的连接的具体操作.下面的也是一样.
Mysql:
public class MysqlStrategy implements Strategy {
	public void getConnDB() {
		/*try {
			Class.forName("com.mysql.jdbc.Driver").newInstance();
			String url = "jdbc:mysql://localhost/myDB?user=root&password=123456&useUnicode=true&characterEncoding=utf-8";
			Connection connection = DriverManager.getConnection(url);
		} catch (SQLException e) {
			e.printStackTrace();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}*/
		System.out.println("connect MySQL");
	}
}

Oracle:
public class OracleStrategy implements Strategy {
	
	public void getConnDB(){
		
		System.out.println("connect  oracle");
		
	}

}

SQL Server:
public class SQLStrategy  implements Strategy{
	public void getConnDB(){
			System.out.println("connect  SQL SERVER");
		}
	}

策略应用场景,方便在运行时动态选择具体要执行的行为.
public class ClientContext {
	Strategy strategy;
	
	public ClientContext(Strategy strategy){
		
		this.strategy=strategy;
	}
	
	public void getConnDB(){
		strategy.getConnDB();
	}

}

下面就开始测试了:
public class StrategyTest {
	public static void main(String[] args) {
		/**
		 * 策略模式实现对Oracle的连接操作.
		 */
		ClientContext occ = new ClientContext(new OracleStrategy());
		occ.getConnDB();
		/**
		 * 策略模式实现对Mysql的连接操作.
		 */
		ClientContext mcc = new ClientContext(new MysqlStrategy());
		mcc.getConnDB();
		/**
		 * 策略模式实现对SQL Server的连接操作.
		 */
		ClientContext scc = new ClientContext(new SQLStrategy());
		scc.getConnDB();

	}

}

    这样,就基本完成通过策略模式动态切换数据库连接的算法.如果想实现对DB2,Sybase,PostgreSQL数据库的操作.只需实现策略接口即可.这样就可以任意扩展.同时对客户(StrategyTest 类)隐藏具体策略(算法)的实现细节,彼此完全独立。完全做到高内聚,低耦合.

     到这里,突然改变需求,需要在数据库连接之前增加一些日志的打印输出.按照传统的做法,我们修改每一个具体的实现类,增加这些功能,如果先前我们实现的具体类非常多.这无异是一笔不小的负担.而且也违反了开闭原则(OCP).
    这里大家可能想到在学习Spring AOP常提到的用AOP打印日志的情景.AOP主要用到了代理模式.这里我们也通过代理模式来实现.由于抽象策略类是接口,所以我们采用JAVA 反射中提供的代理.
   代理模式具体实现:
public class ProxyDB implements InvocationHandler {

	private Object target;

	public ProxyDB(Object target) {
		this.target = target;
	}

	/**
	 * 此处为我们要额外添加的方法 进行日志的打印输出
	 */
	public void printLog() {
		System.out.println("---------------打印输出点日志----------");
	}

	/**
	 * 代理业务处理器
	 */
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Exception {
		printLog();
		return method.invoke(this.target, args);
	}

	public static void main(String[] args) {
		/**
		 * 
		 * 通过代理模式在连接Mysql前增加日志的打印输出;
		 * 
		 */
		MysqlStrategy ms = new MysqlStrategy();
		ProxyDB proxyCorps = new ProxyDB(ms);
		Strategy realObject = (Strategy) Proxy.newProxyInstance(ms.getClass()
				.getClassLoader(), ms.getClass().getInterfaces(), proxyCorps);
		realObject.getConnDB();

		/**
		 * 通过代理模式在连接 Oracle前增加日志的打印输出;
		 * 
		 */
		OracleStrategy os = new OracleStrategy();
		ProxyDB proxyCorps1 = new ProxyDB(os);
		Strategy realObject1 = (Strategy) Proxy.newProxyInstance(os.getClass()
				.getClassLoader(), os.getClass().getInterfaces(), proxyCorps1);
		realObject1.getConnDB();

		/**
		 * 通过代理模式在连接 SQL Ser