设计模式笔记

最近在看设计模式方面的资料.突发灵感,从数据库的连接中联想到了5种设计模式.然后编写了下,都能实现,可能有些实现方式在实际生产环境中并没有意义.就当是对设计模式的学习吧.

首先上演的就是策略模式.我们在连接数据库时,并非一种数据库,比如,有时是MySql,有时是Oracle,有时又换到SQLServer,都要涉及数据库的切换.此时.我们就可以将数据库连接的算法封装起来,使它们可以相互替换.

首先我们定义一个策略接口,用来表示数据库的连接.

Java代码

packagestrategy;

publicinterfaceStrategy{

publicvoidgetConnDB();

}

然后我们实现了对具体的策略类:三大数据库的连接.我们在这里只是强调模式的实现,简单起见,不实现JDBC的连接的具体操作.下面的也是一样.

Mysql:

Java代码

publicclassMysqlStrategyimplementsStrategy{

publicvoidgetConnDB(){

/*try{

Class.forName("com.mysql.jdbc.Driver").newInstance();

Stringurl="jdbc:mysql://localhost/myDB?user=root&password=123456&useUnicode=true&characterEncoding=utf-8";

Connectionconnection=DriverManager.getConnection(url);

}catch(SQLExceptione){

e.printStackTrace();

}catch(InstantiationExceptione){

e.printStackTrace();

}catch(IllegalAccessExceptione){

e.printStackTrace();

}catch(ClassNotFoundExceptione){

e.printStackTrace();

}*/

System.out.println("connectMySQL");

}

}

Oracle:

Java代码

publicclassOracleStrategyimplementsStrategy{

publicvoidgetConnDB(){

System.out.println("connectoracle");

}

}

SQLServer:

Java代码

publicclassSQLStrategyimplementsStrategy{

publicvoidgetConnDB(){

System.out.println("connectSQLSERVER");

}

}

策略应用场景,方便在运行时动态选择具体要执行的行为.

Java代码

publicclassClientContext{

Strategystrategy;

publicClientContext(Strategystrategy){

this.strategy=strategy;

}

publicvoidgetConnDB(){

strategy.getConnDB();

}

}

下面就开始测试了:

Java代码

publicclassStrategyTest{

publicstaticvoidmain(String[]args){

/**

*策略模式实现对Oracle的连接操作.

*/

ClientContextocc=newClientContext(newOracleStrategy());

occ.getConnDB();

/**

*策略模式实现对Mysql的连接操作.

*/

ClientContextmcc=newClientContext(newMysqlStrategy());

mcc.getConnDB();

/**

*策略模式实现对SQLServer的连接操作.

*/

ClientContextscc=newClientContext(newSQLStrategy());

scc.getConnDB();

}

}

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

到这里,突然改变需求,需要在数据库连接之前增加一些日志的打印输出.按照传统的做法,我们修改每一个具体的实现类,增加这些功能,如果先前我们实现的具体类非常多.这无异是一笔不小的负担.而且也违反了开闭原则(OCP).

这里大家可能想到在学习SpringAOP常提到的用AOP打印日志的情景.AOP主要用到了代理模式.这里我们也通过代理模式来实现.由于抽象策略类是接口,所以我们采用JAVA反射中提供的代理.

代理模式具体实现:

Java代码

publicclassProxyDBimplementsInvocationHandler{

privateObjecttarget;

publicProxyDB(Objecttarget){

this.target=target;

}

/**

*此处为我们要额外添加的方法进行日志的打印输出

*/

publicvoidprintLog(){

System.out.println("---------------打印输出点日志----------");

}

/**

*代理业务处理器

*/

publicObjectinvoke(Objectproxy,Methodmethod,Object[]args)

throwsException{

printLog();

returnmethod.invoke(this.target,args);

}

publicstaticvoidmain(String[]args){

/**

*

*通过代理模式在连接Mysql前增加日志的打印输出;

*

*/

MysqlStrategyms=newMysqlStrategy();

ProxyDBproxyCorps=newProxyDB(ms);

StrategyrealObject=(Strategy)Proxy.newProxyInstance(ms.getClass()

.getClassLoader(),ms.getClass().getInterfaces(),proxyCorps);

realObject.getConnDB();

/**

*通过代理模式在连接Oracle前增加日志的打印输出;

*

*/

OracleStrategyos=newOracleStrategy();

ProxyDBproxyCorps1=newProxyDB(os);

StrategyrealObject1=(Strategy)Proxy.newProxyInstance(os.getClass()

.getClassLoader(),os.getClass().getInterfaces(),proxyCorps1);

realObject1.getConnDB();

/**

*通过代理模式在连接SQLServer前增加日志的打印输出;

*

*/

SQLStrategyss=newSQLStrategy();

ProxyDBproxyCorps2=newProxyDB(ss);

StrategyrealObject2=(Strategy)Proxy.newProxyInstance(ss.getClass()

.getClassLoader(),ss.getClass().getInterfaces(),proxyCorps2);

realObject2.getConnDB();

}

}

难道只能通过代理来增加日志功能?这时又突然想到装饰者(Decorator),它本来的目的就是对类的实例追加或扩展附加功能.它可以动态的改变一个对象方法的行为.同时也满足设计原则中的开闭原则.

装饰者模式

(Decorator):

Java代码

publicclassDecoratorimplementsStrategy{

privateStrategystrategy;

publicDecorator(Strategystrategy){

this.strategy=strategy;

}

/**

*额外增加的功能,

*通过装饰者模式动态改变原来对象方法的行为.

*/

publicvoidprintLog(){

System.out.println("---------------先打印输出点日志----------");

}

publicvoidgetConnDB(){

printLog();

strategy.getConnDB();

}

publicstaticvoidmain(String[]args){

/**

*在Oracle连接前增加日志的输出

*/

Decoratordecorator=newDecorator(newOracleStrategy());

decorator.getConnDB();

/**

*在Mysql连接前增加日志的输出

*/

Decoratordecorator1=newDecorator(newMysqlStrategy());

decorator1.getConnDB();

/**

*在Mysql连接前增加日志的输出

*/

Decoratordecorator2=newDecorator(newSQLStrategy());

decorator2.getConnDB();

}

}

呵呵,这里大家可以比较一下代理模式和装饰者模式的区别.

有时候,为了安全起见,我们并不像暴露每个具体的数据库连接类给客户.减少客户与后台具体类的依赖关系.提高子系统的独立性和可移植性.这是需要我们提供一个简单接口,统一跟外界打交道.这时,就该我们的门面模式(Facade)上场了.

Facade外观模式:

为子系统中的一组接口提供一个统一接口。Facade模式定义了一个更高层的接口,使子系统更加容易使用。在构建一个层次化的系统的时候,可以使用Facade模式定义系统的每一层的入口,如果层与层之间是相互依赖的,则可以限定他们仅通过Facade进行通信,从而简化了层与层之间的依赖关系。

同时也实现了软件设计原则中的迪米特法则(LCP).

Java代码

publicclassFacade{

/**

*通过连接操作,提供一个统一的接口,统一跟外界打交道

*减少对具体实现类的依赖.

*

*/

publicvoidgetConn(){

OracleStrategyos=newOracleStrategy();

MysqlStrategyms=newMysqlStrategy();

SQLStrategyss=newSQLStrategy();

os.getConnDB();

ms.getConnDB();

ss.getConnDB();

}

publicstaticvoidmain(String[]args){

newFacade().getConn();

}

}

其实JAVA中的JDBC数据库连接本身也采用了门面模式.

最后一个想到的模式那就是模板模式.这个就没有代码了,大家可以参考Spring所提供的jdbc抽象框架.其核心就是JDBC模板.可能与最开始的想法偏离,就当是一种发散性思维吧.

最后来个简单总结吧,主要实现了五种模式:策略模式,代理模式,装饰者模式,门面模式和模板模式.两大原则:开闭原则和迪米特法则.至于两大原则

策略模式:主要强调算法的封装和自由切换.

代理模式:为其他对象提供一种代理以控制对这个对象的访问.

装饰者模式:动态添加一个类的功能,实现比继承更灵活的扩展方式.

门面模式:系统对外提供一个统一简单的接口,减少系统间的耦合性.

模板模式:将代码的公共行为提取出来,达到复用的目的.

讲得比较简单,就当是抛砖引玉.望大家使劲拍砖.

相关推荐