由JDBC数据库连接所联想到的5种设计模式(转)
2010-05-31 14:15
225 查看
最近在看设计模式方面的资料.突发灵感,从数据库的连接中联想到了5种设计模式.然后编写了下,都能实现,可能有些实现方式在实际生产环境中并没有意义.就当是对设计模式的学习吧.
首先上演的就是策略模式.我们在连接数据库时,并非一种数据库,比如,有时是MySql,有时是Oracle,有时又换到SQL Server,都要涉及数据库的切换.此时.我们就可以将数据库连接的算法封装起来,使它们可以相互替换.
首先我们定义一个策略接口,用来表示数据库的连接.
Java代码
package strategy;
public interface Strategy {
public void getConnDB();
}
然后我们实现了对具体的策略类:三大数据库的连接.我们在这里只是强调模式的实现,简单起见,不实现JDBC的连接的具体操作.下面的也是一样.
Mysql:
Java代码
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:
Java代码
public class OracleStrategy implements Strategy {
public void getConnDB(){
System.out.println("connect oracle");
}
}
SQL Server:
Java代码
public class SQLStrategy implements Strategy{
public void getConnDB(){
System.out.println("connect SQL SERVER");
}
}
策略应用场景,方便在运行时动态选择具体要执行的行为.
Java代码
public class ClientContext {
Strategy strategy;
public ClientContext(Strategy strategy){
this.strategy=strategy;
}
public void getConnDB(){
strategy.getConnDB();
}
}
下面就开始测试了:
Java代码
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 反射中提供的代理.
代理模式具体实现:
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 Server前增加日志的打印输出;
*
*/
SQLStrategy ss = new SQLStrategy();
ProxyDB proxyCorps2 = new ProxyDB(ss);
Strategy realObject2 = (Strategy) Proxy.newProxyInstance(ss.getClass()
.getClassLoader(), ss.getClass().getInterfaces(), proxyCorps2);
realObject2.getConnDB();
}
}
难道只能通过代理来增加日志功能?这时又突然想到装饰者(Decorator),它本来的目的就是对类的实例追加或扩展附加功能.它可以动态的改变一个对象方法的行为.同时也满足设计原则中的开闭原则.
装饰者模式
(Decorator):
Java代码
public class Decorator implements Strategy {
private Strategy strategy;
public Decorator(Strategy strategy) {
this.strategy = strategy;
}
/**
* 额外增加的功能,
* 通过装饰者模式动态改变原来对象方法的行为.
*/
public void printLog() {
System.out.println("---------------先打印输出点日志----------");
}
public void getConnDB() {
printLog();
strategy.getConnDB();
}
public static void main(String[] args) {
/**
* 在Oracle连接前增加日志的输出
*/
Decorator decorator = new Decorator(new OracleStrategy());
decorator.getConnDB();
/**
* 在Mysql连接前增加日志的输出
*/
Decorator decorator1 = new Decorator(new MysqlStrategy());
decorator1.getConnDB();
/**
* 在Mysql连接前增加日志的输出
*/
Decorator decorator2 = new Decorator(new SQLStrategy());
decorator2.getConnDB();
}
}
呵呵, 这里大家可以比较一下代理模式和装饰者模式的区别.
有时候,为了安全起见,我们并不像暴露每个具体的数据库连接类给客户.减少客户与后台具体类的依赖关系.提高子系统的独立性和可移植性. 这是需要我们提供一个简单接口,统一跟外界打交道.这时,就该我们的门面模式(Facade)上场了.
Facade外观模式:
为子系统中的一组接口提供一个统一接口。Facade模式定义了一个更高层的接口,使子系统更加容易使用。在构建一个层次化的系统的时候,可以使用Facade模式定义系统的每一层的入口,如果层与层之间是相互依赖的,则可以限定他们仅通过Facade进行通信,从而简化了层与层之间的依赖关系。
同时也实现了软件设计原则中的迪米特法则(LCP).
Java代码
public class Facade {
/**
*通过连接操作,提供一个统一的接口,统一跟外界打交道
*减少对具体实现类的依赖.
*
*/
public void getConn() {
OracleStrategy os = new OracleStrategy();
MysqlStrategy ms = new MysqlStrategy();
SQLStrategy ss = new SQLStrategy();
os.getConnDB();
ms.getConnDB();
ss.getConnDB();
}
public static void main(String[] args) {
new Facade().getConn();
}
}
其实JAVA 中的JDBC数据库连接本身也采用了门面模式.
最后一个想到的模式那就是模板模式.这个就没有代码了,大家可以参考Spring所提供的jdbc抽象框架.其核心就是JDBC模板.可能与最开始的想法偏离,就当是一种发散性思维吧.
最后来个简单总结吧,主要实现了五种模式:策略模式,代理模式,装饰者模式,门面模式和模板模式.两大原则:开闭原则和迪米特法则.至于两大原则
策略模式 :主要强调算法的封装和自由切换.
代理模式 :为其他对象提供一种代理以控制对这个对象的访问.
装饰者模式:动态添加一个类的功能,实现比继承更灵活的扩展方式.
门面模式 :系统对外提供一个统一简单的接口,减少系统间的耦合性.
模板模式 :将代码的公共行为提取出来,达到复用的目的.
讲得比较简单,就当是抛砖引玉.望大家使劲拍砖.
首先上演的就是策略模式.我们在连接数据库时,并非一种数据库,比如,有时是MySql,有时是Oracle,有时又换到SQL Server,都要涉及数据库的切换.此时.我们就可以将数据库连接的算法封装起来,使它们可以相互替换.
首先我们定义一个策略接口,用来表示数据库的连接.
Java代码
package strategy;
public interface Strategy {
public void getConnDB();
}
package strategy; public interface Strategy { public void getConnDB(); }
然后我们实现了对具体的策略类:三大数据库的连接.我们在这里只是强调模式的实现,简单起见,不实现JDBC的连接的具体操作.下面的也是一样.
Mysql:
Java代码
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");
}
}
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:
Java代码
public class OracleStrategy implements Strategy {
public void getConnDB(){
System.out.println("connect oracle");
}
}
public class OracleStrategy implements Strategy { public void getConnDB(){ System.out.println("connect oracle"); } }
SQL Server:
Java代码
public class SQLStrategy implements Strategy{
public void getConnDB(){
System.out.println("connect SQL SERVER");
}
}
public class SQLStrategy implements Strategy{ public void getConnDB(){ System.out.println("connect SQL SERVER"); } }
策略应用场景,方便在运行时动态选择具体要执行的行为.
Java代码
public class ClientContext {
Strategy strategy;
public ClientContext(Strategy strategy){
this.strategy=strategy;
}
public void getConnDB(){
strategy.getConnDB();
}
}
public class ClientContext { Strategy strategy; public ClientContext(Strategy strategy){ this.strategy=strategy; } public void getConnDB(){ strategy.getConnDB(); } }
下面就开始测试了:
Java代码
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();
}
}
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 反射中提供的代理.
代理模式具体实现:
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 Server前增加日志的打印输出;
*
*/
SQLStrategy ss = new SQLStrategy();
ProxyDB proxyCorps2 = new ProxyDB(ss);
Strategy realObject2 = (Strategy) Proxy.newProxyInstance(ss.getClass()
.getClassLoader(), ss.getClass().getInterfaces(), proxyCorps2);
realObject2.getConnDB();
}
}
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 Server前增加日志的打印输出; * */ SQLStrategy ss = new SQLStrategy(); ProxyDB proxyCorps2 = new ProxyDB(ss); Strategy realObject2 = (Strategy) Proxy.newProxyInstance(ss.getClass() .getClassLoader(), ss.getClass().getInterfaces(), proxyCorps2); realObject2.getConnDB(); } }
难道只能通过代理来增加日志功能?这时又突然想到装饰者(Decorator),它本来的目的就是对类的实例追加或扩展附加功能.它可以动态的改变一个对象方法的行为.同时也满足设计原则中的开闭原则.
装饰者模式
(Decorator):
Java代码
public class Decorator implements Strategy {
private Strategy strategy;
public Decorator(Strategy strategy) {
this.strategy = strategy;
}
/**
* 额外增加的功能,
* 通过装饰者模式动态改变原来对象方法的行为.
*/
public void printLog() {
System.out.println("---------------先打印输出点日志----------");
}
public void getConnDB() {
printLog();
strategy.getConnDB();
}
public static void main(String[] args) {
/**
* 在Oracle连接前增加日志的输出
*/
Decorator decorator = new Decorator(new OracleStrategy());
decorator.getConnDB();
/**
* 在Mysql连接前增加日志的输出
*/
Decorator decorator1 = new Decorator(new MysqlStrategy());
decorator1.getConnDB();
/**
* 在Mysql连接前增加日志的输出
*/
Decorator decorator2 = new Decorator(new SQLStrategy());
decorator2.getConnDB();
}
}
public class Decorator implements Strategy { private Strategy strategy; public Decorator(Strategy strategy) { this.strategy = strategy; } /** * 额外增加的功能, * 通过装饰者模式动态改变原来对象方法的行为. */ public void printLog() { System.out.println("---------------先打印输出点日志----------"); } public void getConnDB() { printLog(); strategy.getConnDB(); } public static void main(String[] args) { /** * 在Oracle连接前增加日志的输出 */ Decorator decorator = new Decorator(new OracleStrategy()); decorator.getConnDB(); /** * 在Mysql连接前增加日志的输出 */ Decorator decorator1 = new Decorator(new MysqlStrategy()); decorator1.getConnDB(); /** * 在Mysql连接前增加日志的输出 */ Decorator decorator2 = new Decorator(new SQLStrategy()); decorator2.getConnDB(); } }
呵呵, 这里大家可以比较一下代理模式和装饰者模式的区别.
有时候,为了安全起见,我们并不像暴露每个具体的数据库连接类给客户.减少客户与后台具体类的依赖关系.提高子系统的独立性和可移植性. 这是需要我们提供一个简单接口,统一跟外界打交道.这时,就该我们的门面模式(Facade)上场了.
Facade外观模式:
为子系统中的一组接口提供一个统一接口。Facade模式定义了一个更高层的接口,使子系统更加容易使用。在构建一个层次化的系统的时候,可以使用Facade模式定义系统的每一层的入口,如果层与层之间是相互依赖的,则可以限定他们仅通过Facade进行通信,从而简化了层与层之间的依赖关系。
同时也实现了软件设计原则中的迪米特法则(LCP).
Java代码
public class Facade {
/**
*通过连接操作,提供一个统一的接口,统一跟外界打交道
*减少对具体实现类的依赖.
*
*/
public void getConn() {
OracleStrategy os = new OracleStrategy();
MysqlStrategy ms = new MysqlStrategy();
SQLStrategy ss = new SQLStrategy();
os.getConnDB();
ms.getConnDB();
ss.getConnDB();
}
public static void main(String[] args) {
new Facade().getConn();
}
}
public class Facade { /** *通过连接操作,提供一个统一的接口,统一跟外界打交道 *减少对具体实现类的依赖. * */ public void getConn() { OracleStrategy os = new OracleStrategy(); MysqlStrategy ms = new MysqlStrategy(); SQLStrategy ss = new SQLStrategy(); os.getConnDB(); ms.getConnDB(); ss.getConnDB(); } public static void main(String[] args) { new Facade().getConn(); } }
其实JAVA 中的JDBC数据库连接本身也采用了门面模式.
最后一个想到的模式那就是模板模式.这个就没有代码了,大家可以参考Spring所提供的jdbc抽象框架.其核心就是JDBC模板.可能与最开始的想法偏离,就当是一种发散性思维吧.
最后来个简单总结吧,主要实现了五种模式:策略模式,代理模式,装饰者模式,门面模式和模板模式.两大原则:开闭原则和迪米特法则.至于两大原则
策略模式 :主要强调算法的封装和自由切换.
代理模式 :为其他对象提供一种代理以控制对这个对象的访问.
装饰者模式:动态添加一个类的功能,实现比继承更灵活的扩展方式.
门面模式 :系统对外提供一个统一简单的接口,减少系统间的耦合性.
模板模式 :将代码的公共行为提取出来,达到复用的目的.
讲得比较简单,就当是抛砖引玉.望大家使劲拍砖.
相关文章推荐
- 转:由JDBC数据库连接所联想到的五种设计模式
- 由JDBC数据库连接所联想到的五种设计模式
- 使用单例模式设计JDBC连接数据库
- JDBC连接数据库(单例设计模式)
- JDBC实现增删改查、模糊查询、分页查询、子查询以及体现单例设计模式连接数据库
- sparkStreaming 连接数据库 --设计模式
- sparkStreaming 连接数据库 --设计模式
- JDBC 连接数据库之单例模式
- JDBC连接MYSQL的DAO设计模式
- 使用JDBC的连接数据库的步骤和DAO模式的使用
- PHP面向对象:单态设计模式(连接数据库)
- 复习下单例设计模式(实现数据库连接,以免多次实例化)
- DAO设计模式实现数据库的增删改查(进一步封装JDBC工具类)
- 黑马程序员 JDBC_通过代理模式来保持用户关闭连接的习惯,代理设计模式(李勇老师)
- 单例设计模式中使用dom4j来完成(数据库配置文件)xml的解析,并完成数据库的连接
- Hibernate、SpringJDBC中在注解模式下获取数据库连接
- JDBC数据库连接、设计以及备份技巧集锦
- JAVA用JDBC模式简单的连接数据库
- 单例模式在JDBC数据库连接操作里的应用
- MySQL数据库学习笔记(十一)----DAO设计模式实现数据库的增删改查(进一步封装JDBC工具类)