Java学习者论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

手机号码,快捷登录

恭喜Java学习者论坛(https://www.javaxxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,购买链接:点击进入购买VIP会员
JAVA高级面试进阶视频教程Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程

Go语言视频零基础入门到精通

Java架构师3期(课件+源码)

Java开发全终端实战租房项目视频教程

SpringBoot2.X入门到高级使用教程

大数据培训第六期全套视频教程

深度学习(CNN RNN GAN)算法原理

Java亿级流量电商系统视频教程

互联网架构师视频教程

年薪50万Spark2.0从入门到精通

年薪50万!人工智能学习路线教程

年薪50万!大数据从入门到精通学习路线年薪50万!机器学习入门到精通视频教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程 MySQL入门到精通教程
查看: 348|回复: 0

[设计模式学习]由JDBC数据库连接所联想到的五种设计模式

[复制链接]
  • TA的每日心情
    开心
    2021-3-12 23:18
  • 签到天数: 2 天

    [LV.1]初来乍到

    发表于 2014-11-3 00:00:34 | 显示全部楼层 |阅读模式
    最近在看设计模式方面的资料.突发灵感,从数据库的连接中联想到了5种设计模式.然后编写了下,都能实现,可能有些实现方式在实际生产环境中并没有意义.就当是对设计模式的学习吧.
          首先上演的就是策略模式.我们在连接数据库时,并非一种数据库,比如,有时是MySql,有时是Oracle,有时又换到SQL Server,都要涉及数据库的切换.此时.我们就可以将数据库连接的算法封装起来,使它们可以相互替换.
          首先我们定义一个策略接口,用来表示数据库的连接.
    package strategy;
    public interface Strategy {
            public void getConnDB();
    }
      [/code]     然后我们实现了对具体的策略类:三大数据库的连接.我们在这里只是强调模式的实现,简单起见,不实现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");
            }
    }
          [/code] Oracle:
    public class OracleStrategy implements Strategy {
           
            public void getConnDB(){
                   
                    System.out.println("connect  oracle");
                   
            }
    }[/code] SQL Server:
    public class SQLStrategy  implements Strategy{
            public void getConnDB(){
                            System.out.println("connect  SQL SERVER");
                    }
            }[/code]
    策略应用场景,方便在运行时动态选择具体要执行的行为.
    public class ClientContext {
            Strategy strategy;
           
            public ClientContext(Strategy strategy){
                   
                    this.strategy=strategy;
            }
           
            public void getConnDB(){
                    strategy.getConnDB();
            }
    }
          [/code] 下面就开始测试了:
    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();
            }
    }
          [/code]     这样,就基本完成通过策略模式动态切换数据库连接的算法.如果想实现对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 Server前增加日志的打印输出;
                     *
                     */
                    SQLStrategy ss = new SQLStrategy();
                    ProxyDB proxyCorps2 = new ProxyDB(ss);
                    Strategy realObject2 = (Strategy) Proxy.newProxyInstance(ss.getClass()
                                    .getClassLoader(), ss.getClass().getInterfaces(), proxyCorps2);
                    realObject2.getConnDB();
            }
    }
          [/code]     难道只能通过代理来增加日志功能?这时又突然想到装饰者(Decorator),它本来的目的就是对类的实例追加或扩展附加功能.它可以动态的改变一个对象方法的行为.同时也满足设计原则中的开闭原则.
          装饰者模式
    (Decorator): 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();
            }
    }
          [/code]
            呵呵, 这里大家可以比较一下代理模式和装饰者模式的区别.

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

    Facade外观模式
         为子系统中的一组接口提供一个统一接口。Facade模式定义了一个更高层的接口,使子系统更加容易使用。在构建一个层次化的系统的时候,可以使用Facade模式定义系统的每一层的入口,如果层与层之间是相互依赖的,则可以限定他们仅通过Facade进行通信,从而简化了层与层之间的依赖关系。
         同时也实现了软件设计原则中的迪米特法则(LCP).
    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();
            }
    }
    [/code] 其实JAVA 中的JDBC数据库连接本身也采用了门面模式.
          最后一个想到的模式那就是模板模式.这个就没有代码了,大家可以参考Spring所提供的jdbc抽象框架.其核心就是JDBC模板.可能与最开始的想法偏离,就当是一种发散性思维吧.
           最后来个简单总结吧,主要实现了五种模式:策略模式,代理模式,装饰者模式,门面模式和模板模式.两大原则:开闭原则和迪米特法则.至于两大原则
         策略模式  :主要强调算法的封装和自由切换.
         代理模式  :为其他对象提供一种代理以控制对这个对象的访问.
         装饰者模式:动态添加一个类的功能,实现比继承更灵活的扩展方式.
         门面模式  :系统对外提供一个统一简单的接口,减少系统间的耦合性.
         模板模式  :将代码的公共行为提取出来,达到复用的目的.
    讲得比较简单,就当是抛砖引玉.望大家使劲拍砖.
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|Java学习者论坛 ( 声明:本站资料整理自互联网,用于Java学习者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2025-2-25 15:53 , Processed in 0.369174 second(s), 48 queries .

    Powered by Discuz! X3.4

    © 2001-2017 Comsenz Inc.

    快速回复 返回顶部 返回列表