原文源于开发高手2004年12期——深入剖析Java的动态特性和接口编程模型
读了这篇文章之后,我对接口概念的理解又深了一层,不仅仅停留在“优先使用接口,而非类继承”的层次上了。
接口,实际上就是服务的提供者,调用接口的一方,就是服务的调用者,凡是实现了同一个接口的对象,都可以向服务的调用者提供相同的服务。
文章中最开始介绍的方法就是new一个服务提供者,通过它来向调用者提供所需的资源,这种方法是最简单的,同时也是耦合性最强的,因为使用这种方式的前提条件,就是服务调用者必须知道服务提供者,当服务提供者可变而且必须在系统运行时才能确定的时候,这种方法也就不能用了。
于是,文章中又提出了interface+Class.forName()的模型,通过Class.forName(),我们动态的加载了服务实现,而通过使用interface,我们的服务调用者又可以预先获得这个服务提供者所提供的服务,即使在编译的时候我们并没有真正的获得服务提供者的资源,但是接口已经规定了所有的服务提供者所必须遵守的契约,这样服务调用者可以完全相信动态获得得这个服务提供者的资源是符合条件的资源。
紧接着,作者又通过分析JDBC的API来进一步分析接口与动态加载的使用。
JDBC API在使用过程中不用考虑各个数据库实现的差异,而采用统一的方式进行编码,但是各个数据库厂商的核心引擎是不一样的,那么该如何采用一致的方式访问呢?结合上面的分析得到,这又是一个服务提供者可变而且在运行时才确定的例子。
最基本的方法就是采用Class.forname()方法来加载驱动对象,然后获得连接。稍稍优化一些的方式就是把驱动对象,url都写在配置文件中,更改驱动的时候,只需要更改配置文件就可以了。
这种方法就是服务的调用者对接口进行编程,然后通过动态加载的方式来获得具体的服务提供者。但是这种方法依然具有较高的耦合性,正确的方法应该是被动的接受服务提供者所提供的服务,而不是主动请求服务提供者对它提供服务,这样子才能够完全解耦,才可以避免服务调用者对服务提供者的依赖性。而上面的方法中,无论是修改程序,还是修改配置文件,都是要进行修改的,也就是非独立。
更好一点的方法就是J2EE里面的JNDI+工厂方法了,只要把外部服务器的连接配置成功,就可以用JNDI查找获得抽象的服务资源工厂,然后通过这个工厂生成所需要的服务,这样无论如何改动数据库驱动,程序的代码都无需更改。如:
InitialContext ctx = new InitialContext();
DataSource ds = (DataSource)ctx.lookup(“xxx”);
= ds.getConnection();
这种方式仅仅依赖于外部环境了,按照作者的观点,采用依赖注入就可以让服务调用者完全是被动的获得服务提供者的服务,但是这些我还没有看到过,还有待于以后的学习。