一个体现Java接口及工厂模式优点的例子

本文涉及的产品
云数据库 RDS SQL Server,基础系列 2核4GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS SQL Server Serverless,2-4RCU 50GB 3个月
推荐场景:
简介:
原2004年初发于CSDN,后图片丢失,现补上。陈刚 from  www.chengang.com.cn


     随着模式概念的普及,了解模式和使用模式的程序员越来越多,很多人在学习模式的时候,都会有这样一种疑惑:“有必要搞得这么复杂吗?”。的确,因为教程的例子过于简单化(这样方便读者学习),或者是作者选例子的时候并没有很好体现所讲模式的优点,很多情况下如果仅就其例子的问题来说,用模式是太复杂了。因此才导致这样的误解:“模式就是把简单的问题复杂化吗?”。当然不是,随着你开发实践的不断丰富,你终会发现模式强大威力,而且模式也并非贵族化的编程方式,它就是一些经过提炼了的解决问题的方法技巧。
 
      通过学习模式,程序员开始告别过去准直线式的代码方式,模式开扩了我们的视野,强化了我们面向对象编程的思维方式。然而现在又出现了另一个普遍的问题,盲目应用模式。模式是问题的解决方案,先有问题才有模式,模式是依附于所要解决的问题的而生的。必须了解模式在很多情况下是以提高代码的复杂度为代价来增强灵活性、可复用性。如果在自已的代码中使用某一模式仅只提高了代码的复杂度,而其它方面收效甚微,或者某部份代码根本就不存在灵活性及高复用性的需求,那么我们就没有必要为使用模式而放弃更直观简单的代码写法。
 
      一流的高手90%精力关注问题的解决方案,因为找到了好的解决方案,再写起代码会很轻松代码也简洁流畅,看这样的代码是一种享受和提高;二流的熟手90%精力关注代码实现,因为问题的解决方案并非最佳,实现的代码也会比较复杂;三流菜鸟记流水帐,90%精力在敲键盘,常常做了大半才发现行不通,回过头来再用90%的时间敲键盘,根本不会用到任何模式,写出来的代码的只有他自已才能看懂。做出来的软件也是支离破碎,做一丁点改动都要大费周折,而且你还不知道改动后会产生什么问题,大有住危房里的感觉。
 
      在这里还是举一个滥用模式的例子吧。我曾参与过一个大集团公司OA系统的第二期开发,开发沿用原有代码架构并增加新的功能模块。文档很少我读原代码时就被它程序里的代码转来转去搞得头大如斗,最后读懂了:原代码架构总体采用工厂模式,而且是最复杂的抽象工厂模式。它把所有模块类都通过工厂生成还工厂套工厂,并且每一个模块类都有一个接口,每个接口也只有一个模块现实类,因为涉及权限控制还用了代理(proxy)模式。 读懂代码后我开始嵌入代码,发现每新增一个类,都要到六个Java文件中去增加相应代码,而在类中每增加一个方法,也要到它的接口等四个Java文件中去增加相应代码。天呀!!!记得当时我的小姆指常会不听使唤,就是因为频繁的使用Ctrl+C 、Ctrl+V,小姆指按着Ctrl键给累的。整个项目组苦不堪言,真烦透了。项目结束后我回顾发现:代理模式用得还对(现在针对权限这类横向控制有AOP编程这种新的解决办法了)但工厂模式在这里根本就是画蛇添足,不仅没有解决什么问题,反而增加代码复杂度和耦合性,降低了开发效率连维护难度都提高了。而且那种每个类简单的加一个接口的方式,更是没有道理,这让我很想说周星驰说过的一句话:“球~~~不是这么踢~~~~的,接口~~~不是这么用~~~的”。言归正传,我们先来看这样一个常见问题:某系统需要支持多种类型的数据库。用过Oracle、MSSQL等数据库的人都知道,它们的SQL编写方式都各有些不同。比如说Oracle的唯一标识自动+1字段用的是序列,MSSQL改一下字段属性就成了,还有各种各自特有的SQL用法。为了支持多数据库,难道我们要开发多套系统?当然NO。请看下面的解决方案。
 
      即然数据库存在多种,我们可以将系统中所有对数据库的操作抽象出来,写成一个个方法组合到一个类中,有几种数据库我们就写几个这样的类。具体设计类图如下:
20060910.gif
 
 
简要说明:
  • OracleDataOperate、SqlserverDataOperate、MysqlDataOperate,分别代表Oracle、Sqlserver、Mysql这三种数据库的操作类。继承自AbstractDataOperate
  • AbstractDataOperate是一个抽象类,包含了那些不同种类数据库都是一样代码的操作方法。继承自DataOperate
  • DataOperate是上面说的数据操作类的统一接口,只有两个方法:取得一条记录、插入一条记录。
  • DataOperateFactory是一个工厂方法,统一用它的方法来得到数据库操作类的实例。
  • SampleClass是我们系统的某个功能模块的类。
  • People是一个实体类,代表一条记录。三个字段 oid唯一标识符、name姓名、date生日。
 
详细说明:
1、所有系统功能模块类只认DataOperat这个接口还不必管具体的实现类是OracleDataOperate还SqlserverDataOperate。DataOperate源代码如下:
public interface DataOperate {
    //根据记录的唯一标识取出一条记录
    People getPeople(String oid);
    //插入一条记录
     boolean insertPeople(People people);
}
 
2、AbstractDataOperate、OracleDataOperate、SqlserverDataOperate、MysqlDataOperate都是继承DataOperate接口的,没什么好说的,省略。
 
3、DataOperateFactory。我们看看工厂方法怎么写的。
public class DataOperateFactory {
     public static final int ORACLE = 0; //定义三个表示数据库类型的常量
     public static final int MYSQL = 1;
     public static final int SQLSERVER = 2;
 
     private static DataOperate db;
     private static int dataType = MYSQL;
    /**
     * 根据数据库类型(dataType)取得一个数据库操作类的实例,
     * 这里对DataOperate使用了单例模式,因为OracelDataOperate等都是无状态的工具类,
     * 所以整个系统只保留一个实例就行了。
     *
     *  @return 返回的是接口,客户端不必关心具体是用那个实现类
     */
     public static DataOperate getInstance() {
         if (db ==  null) {
             if (dataType == ORACLE) //根据dateType返回相应的实现类
                 return new OracelDataOperate();
             if (dataType == MYSQL)
                 return new MysqlDataOperate();
             if (dataType == SQLSERVER)
                 return new SqlserverDataOperate();
        }
         return db;
    }
}
 
4、接下来就看看使用端是如何调用工厂方法和使用数据操作类的。
/**
 * 系统某个功能类
 */
public class SampleClass {
private DataOperate db; //声明一个数据库操作类,注意这里用的是接口噢
    /**某方法*/
     public void sampleMethod() {
        db = DataOperateFactory.getInstance();//得到单一实例
        People p = db.getPeople("123"); //取得一条记录
        db.insertPeople(p);//再插回去
    }
}
 
  我们发现SampleClass中根本没有出现OracelDataOperate、MysqlDataOperate等的影子,这就是接口的威力。客户端不必针对OracelDataOperate等写不同的代码,它只关心DataOperate即可,具体要取那个类的逻辑就由DataOperateFactory负责了。
 
总结:
  • 从例子中我们可以看到什么是面向接口的编程方式。SampleClass使用数据操作类可以不必关心具体是那个类,只要是符合接口的都行
  • 要实例?只须调用DataOperateFactory.getInstance()即可,其它的交于DataOperateFactory这个工厂来做吧,使用端什么都不用关心。
  • 我们要支持新的数据库类型,只须要象OracelDataOperate那样,再写一个继承AbstractDataOperate的类即可,比如SysbaseDataOperate。然后到DataOperateFactory中加入相应代码即可。
  • 如果我们想要可配置性更高,可以用 private static int dataType = MYSQL;中的值设置到一个文本文件中。
  对于开发支持多种数据库的系统,强烈建议使用hibernate,我现在做的系统就是用hibernate的,开发时用Mysql,到要给客户时将数据库换了DB2,程序不用做任何改动,真正的无逢移植。不过这样,本文所提到的方法就没什么用了.
相关实践学习
如何快速连接云数据库RDS MySQL
本场景介绍如何通过阿里云数据管理服务DMS快速连接云数据库RDS MySQL,然后进行数据表的CRUD操作。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
4月前
|
JSON Java Apache
非常实用的Http应用框架,杜绝Java Http 接口对接繁琐编程
UniHttp 是一个声明式的 HTTP 接口对接框架,帮助开发者快速对接第三方 HTTP 接口。通过 @HttpApi 注解定义接口,使用 @GetHttpInterface 和 @PostHttpInterface 等注解配置请求方法和参数。支持自定义代理逻辑、全局请求参数、错误处理和连接池配置,提高代码的内聚性和可读性。
306 3
|
1月前
|
缓存 Java 应用服务中间件
java语言后台管理若依框架-登录提示404-接口异常-系统接口404异常如何处理-登录验证码不显示prod-api/captchaImage 404 (Not Found) 如何处理-解决方案优雅草卓伊凡
java语言后台管理若依框架-登录提示404-接口异常-系统接口404异常如何处理-登录验证码不显示prod-api/captchaImage 404 (Not Found) 如何处理-解决方案优雅草卓伊凡
149 5
|
4月前
|
Java
在Java中如何实现接口?
实现接口是 Java 编程中的一个重要环节,它有助于提高代码的规范性、可扩展性和复用性。通过正确地实现接口,可以使代码更加灵活、易于维护和扩展。
271 64
|
4月前
|
Java
在Java中,接口之间可以继承吗?
接口继承是一种重要的机制,它允许一个接口从另一个或多个接口继承方法和常量。
372 60
|
4月前
|
Java 开发者
在 Java 中,一个类可以实现多个接口吗?
这是 Java 面向对象编程的一个重要特性,它提供了极大的灵活性和扩展性。
225 58
|
4月前
|
Java
在Java中实现接口的具体代码示例
可以根据具体的需求,创建更多的类来实现这个接口,以满足不同形状的计算需求。希望这个示例对你理解在 Java 中如何实现接口有所帮助。
135 38
|
3月前
|
数据采集 JSON Java
利用Java获取京东SKU接口指南
本文介绍如何使用Java通过京东API获取商品SKU信息。首先,需注册京东开放平台账号并创建应用以获取AppKey和AppSecret。接着,查阅API文档了解调用方法。明确商品ID后,构建请求参数并通过HTTP客户端发送请求。最后,解析返回的JSON数据提取SKU信息。注意遵守API调用频率限制及数据保护法规。此方法适用于电商平台及其他数据获取场景。
|
3月前
|
安全 Java API
java如何请求接口然后终止某个线程
通过本文的介绍,您应该能够理解如何在Java中请求接口并根据返回结果终止某个线程。合理使用标志位或 `interrupt`方法可以确保线程的安全终止,而处理好网络请求中的各种异常情况,可以提高程序的稳定性和可靠性。
68 6
|
4月前
|
Java API
Java中内置的函数式接口
Java中内置的函数式接口
58 2
|
4月前
|
Java Android开发
Eclipse 创建 Java 接口
Eclipse 创建 Java 接口
57 1

热门文章

最新文章