在Java API设计中,面向接口编程的思想,以及接口和工厂的关系

现在的java API的设计中,提倡面向接口的编程,即在API的设计中,参数的传递和返回建议使用接口,而不是具体的实现类,如一个方法的输入参数类型应该使用Map接口,而不是HashMap或Hashtable等具体的实现类。这样做的好处是,程序容易扩展。如果使用Map作为参数,用户可以使用任何实现Map接口的类作为参数,而不是仅仅限制使用HashMap或Hashtable作为参数,使程序的实现更加灵活。

  接口(Java的Interface),只定义了一些抽象的方法(也可以定义一些常量,但不鼓励这么做),没有具体的实现,这些抽象方法的具体实现,必须由实现(implements)接口的具体类来实现。接口反映了系统设计人员对系统的抽象理解。实际上,接口只是定义了一个规范和约束,要求实现类必须遵循这些规范和约束,大家编程时都要按照这个规范进行编程。

  使用接口进行编程时,API的使用者只使用接口进行调用,而不管接口是如何实现的,这样你就可以随意更换接口的实现厂商(provider)。假如,你觉得厂商的接口实现不好,可以换一个厂商的实现类,甚至自己来实现,但确基本上不需要更改已经写好的应用程序(因为应用程序只对接口进行调用,而所有的实现类的接口都是相同的)。

  如java.sql包定义了很多jdbc的接口,大家在进行jdbc编程时都只需要使用Connection、PreparedStatment、ResultSet等接口,而不需要考虑这些接口的具体实现类是什么。每种数据库,如Oracle、SQLServer、DB2的JDBC驱动则是由各个厂商提供具体实现类,来实现统一的JDBC API接口规范。

  面向接口的编程中,工厂(Factory)的使用恐怕是最常用的,接口和工厂的关系是密不可分的,工厂,简单的说,就是生产接口实现类实例的类。可以说,在面向接口的编程中,工厂方法发挥了极其重要的作用。

  在开发应用时,如何对接口进行调用,如何实例化接口对象?你无法通过类似于new Inteface1()等来进行实例化,因为接口是不能实例化的(接口即Java的Interface不是类,所有方法都是抽象的,所以不能实例化,能够实例化的只能是接口的实现类)。实例化接口类对象主要有两种方法:

1) 直接new 接口的实现类的实例,类似于

Map map=new HashMap(); //HashMap实现了Map接口

Interface1 instance=new ConcreteClass1();  //ConcreteClass1实现了Inteface1接口

  在一个API内部,这样写无可厚非,因为对调用者是屏蔽的,你今后将HashMap改为hashtable,不会影响到API调用者的程序。但是对于一个API调用的程序来说,这样就不太好了。如下面的调用(出租车公司增加一种高级轿车):

Car car=new BenzCar(); //BenzCar实现了Car接口

carRentCompany.addSuperCar(car);

  虽然可以这样,但这与面向接口的编程的原则不符,因为这要求你必须要知道接口的实现类,如果你有天想换一个实现类(如将奔驰车换成宝马车),就麻烦了,你必须找到你以前的应用程序源代码,将每一个调用接口实现类的地方都改过来,工作量比较大了。

  还有一种更好的方法,就是使用工厂。

2) 使用工厂,如

Car car=CarFactory.getSuperCar();

carRentCompany.addSuperCar(car);

  由工厂来提供实例化方法,你不必关心实例化类是哪一个。当然你必须知道工厂类是哪一个,更换接口实现的时候,你只需要修改工厂的方法就可以了,其余的都不需要更改了。如上面的场景,将奔驰车换成宝马车,只要更改CarFactory.getSuperCar()方法就可以了,用户调用API的程序不需要修改。

  举个jdbc调用的例子:

Oracle的jdbc调用:

... ...

Class.forName("oracle.jdbc.driver.OracleDriver";);

Connection conn=DriverManager.getConnection(jdbcurl,username,password);

SQLServer的jdbc调用:

... ...

Class.forName("com.microsoft.jdbc.sqlserver.SQLServerDriver");

Connection conn=DriverManager.getConnection(jdbcurl,username,password);

MySQL的jdbc调用:

... ...

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

Connection conn=DriverManager.getConnection(jdbcurl,username,password);

  这里,DriverManager就是工厂,通过getConnection()方法来生产出数据库连接对象Connection, 用户使用Connect就可以实现JDBC编程了。

  但是,DriverManager是怎么知道使用的哪个数据库,使用哪个提供商的JDBC驱动来生产Connectin的吗?答案在这里,原因就在Class.forName()的过程中,Class.forName()是将一个类初始化,这里,调用不同厂商提供jdbc驱动时,使用了不同的jdbc驱动类的类名,该方法会初始化化该Driver类,该类在初始化时(static{}方法中)会初始化一个自己的Driver类实例,并将实例注册到DriverManager中(的一个Vector中),再通过DriverManager中的getConnection()方法找到Driver实例(通过jdbcurl),再调用Driver实例的getConnection()方法。Driver实例也是一个生产Connection接口实例的工厂。DriverManager实际上是一个保存了各个jdbc驱动的一个缓存管理类,缓存了各个驱动程序,并调用各个jdbc的驱动程序生产Connection对象。

  可以看出,只需要更改Driver的类名,提供不同的jdbcUrl和用户、密码,就可以生产出一个数据库连接(Connection接口类的实例)。

  建议:如果你使用配置文件来提供工厂类的名字,程序通过调用配置文件来读取工厂的类名,更换接口实现就更简单了,你只需要改配置文件就可以了,而不需要更改程序。

接口和工厂之间关系形象比喻:

  接口就好比是产品规格,如螺母和螺钉的产品规格,规定了不同的大小尺寸,左旋等,工厂好比生产这些螺母和螺钉的加工企业,而接口的实例好比不同工厂生成出的螺母、螺钉的产品。每一个不同的工厂虽然生成出的不同螺母和螺钉产品,但都必须遵守这个产品规格,这样不同工厂生产出来的不同的螺母和螺钉才可以拧在一起使用,你也可以随意更换不同工厂生产出来的螺母或螺钉,而不会出现问题。

http://blog.sina.com.cn/s/blog_6f505d710100mxsy.html

时间: 2024-12-25 08:11:37

在Java API设计中,面向接口编程的思想,以及接口和工厂的关系的相关文章

(转)Java API设计清单

转自: 伯乐在线 Java API设计清单 英文原文 TheAmiableAPI 在设计Java API的时候总是有很多不同的规范和考量.与任何复杂的事物一样,这项工作往往就是在考验我们思考的缜密程度.就像飞行员起飞前的检查清单,这张清单将帮助软件设计者在设计Java API的过程中回忆起那些明确的或者不明确的规范.本文也可以看作为“API设计指南”这篇文章的附录. 我们还准备了一些前后比对的例子来展示这个列表如何帮助你理清设计需求,找出错误,识别糟糕的设计实践以及如何寻找改进的时机. 这个清单

Java API 设计清单

译者:[email protected]东西 来源:http://blog.jobbole.com/12958/ 在设计Java API的时候总是有很多不同的规范和考量.与任何复杂的事物一样,这项工作往往就是在考验我们思考的缜密程度.就像飞行员起飞前的检查清单,这张清单将帮助软件设计者在设计Java API的过程中回忆起那些明确的或者不明确的规范.本文也可以看作为“API设计指南”这篇文章的附录. 我们还准备了一些前后比对的例子来展示这个列表如何帮助你理清设计需求,找出错误,识别糟糕的设计实践以

【设计模式】设计原则--面向接口编程你理解的对吗?

最近看了<Head First Design Patterns>这本书.正如其名,这本书讲的是设计模式(Design Patterns),而这本书的第一章,讲的是很重要的一些设计原则(Design Principles). Identify the aspects of your application that vary and separate them from what stays the same.(识别应用程序中各个方面的变化,并将它们与保持不变的部分分开.) Program to

API设计中防重放攻击

HTTPS数据加密是否可以防止重放攻击? 否,加密可以有效防止明文数据被监听,但是却防止不了重放攻击. 防重放机制 我们在设计接口的时候,最怕一个接口被用户截取用于重放攻击.重放攻击是什么呢?就是把你的请求原封不动地再发送一次,两次...n次,一般正常的请求都会通过验证进入到正常逻辑中,如果这个正常逻辑是插入数据库操作,那么一旦插入数据库的语句写的不好,就有可能出现多条重复的数据.一旦是比较慢的查询操作,就可能导致数据库堵住等情况.付款接口,或者购买接口会造成损失需要采用防重放的机制来做请求验证

JAVA GUI设计中遇到的一个小问题

最近新学,大牛勿喷.. 写下笔记主要是记录自己常犯的错误,也方便新人解决问题学习参考. 问题:win7下设计GUI,文本框和密码框显示不出来. 我的解决方案: 1. JTextField text = new JTextField(JTextField.RIGHT); JPasswordField pass = new JPasswordField(JPasswordField.RIGHT); 2. JTextField text = new JTextField(10); JPasswordF

通俗简述 依赖倒置?控制反转?依赖注入?面向接口编程 的思想

不管怎样我们都是为了提倡高内聚和低耦合的思想,这么多种思想是不是看那些概念头晕的不行呢? 这里我们主要列举吃饭的例子让大家更直观的理解这几个概念,现在有顾客(客户端)与餐厅(服务端)两个对象 依赖倒置: 餐厅建立订餐通道  (本来是顾客依赖餐厅炒菜的,开通饿了吗后餐厅就倒过来依赖ele的订单去炒菜了) 控制反转IOC(Inversion Of Control):  改成自助餐厅(以前餐厅炒的菜分量太少了,现在菜都摆出来了你可以自己选择量多的菜了) 依赖注入DI(Dependency Inject

Java面向对象设计的六大原则

这是设计模式系列开篇的第一篇文章.也是我学习设计模式过程中的总结.这篇文章主要讲的是面向对象设计中,我们应该遵循的六大原则.只有掌握了这些原则,我们才能更好的理解设计模式.我们接下来要介绍以下6个内容. 单一职责原则——SRP 开闭原则——OCP 里式替换原则——LSP 依赖倒置原则——DIP 接口隔离原则——ISP 迪米特原则——LOD 单一职责原则 单一职责原则的定义是就一个类而言,应该仅有一个引起他变化的原因.也就是说一个类应该只负责一件事情.如果一个类负责了方法M1,方法M2两个不同的事

出色的 JavaScript API 设计秘诀

设计是一个很普遍的概念,一般是可以理解为为即将做的某件事先形成一个计划或框架. (牛津英语词典)中,设计是一种将艺术,体系,硬件或者更多的东西编织到一块的主线.软件设计,特别是作为软件设计的次类的API设计,也是一样的.但是API设计常常很少关注软件发展,因为为其他程序员写代码的重要性要次于应用UI设计和最终用户体验. 但是API设计,作为我们自己写的库中提供的公共接口,能够向调用我们代码的开发者表现出我们库的一些特点和功能,所以API设计和UI设计一样重要.事实上,两者都是为应用可以提供更好的

Java数据库设计14个技巧

Java数据库设计14个技巧   1. 原始单据与实体之间的关系 可以是一对一.一对多.多对多的关系.在一般情况下,它们是一对一的关系:即一张原始单据对应且只对应一个实体.在特殊情况下,它们可能是一对多或多对一的关系,即一张原始单证对应多个实体,或多张原始单证对应一个实体.这里的实体可以理解为基本表.明确这种对应关系后,对我们设计录入界面大有好处. [例1]:一份员工履历资料,在人力资源信息系统中,就对应三个基本表:员工基本情况表.社会关系表.工作简历表.   这就是"一张原始单证对应多个实体&