读书人

浅谈Java内部类的四个运用场景

发布时间: 2012-12-19 14:13:14 作者: rapoo

浅谈Java内部类的四个应用场景
Java内部类是Java言语的一个很重要的概念,《Java编程思想》花了很大的篇幅来讲述这个概念。但是我们在实践中很少用到它,虽然我们在很多时候会被动的使用到它,但它仍然像一个幕后英雄一样,不为我们所知,不为我们所用。
本文不试图来讲述Java内部类的今生前世、来龙去脉,这些在网络上都已经汗牛充栋。如果读者想了解这些,可以在网络上搜索来学习。Java内部类总是躲在它的外部类里,像一个幕后英雄一样。但是幕后英雄也有用武之地,在很多时候,恰当的使用Java内部类能起到让人拍案叫绝的作用。本文试图谈一谈让这个幕后英雄也有用武之地的四个场景,希望引起大家对使用Java内部类的兴趣。
以下的文字,要求大家熟悉Java内部类的概念后来阅读。


场景一:当某个类除了它的外部类,不再被其他的类使用时

我们说这个内部类依附于它的外部类而存在,可能的原因有:1、不可能为其他的类使用;2、出于某种原因,不能被其他类引用,可能会引起错误。等等。这个场景是我们使用内部类比较多的一个场景。下面我们以一个大家熟悉的例子来说明。
在我们的企业级Java项目开发过程中,数据库连接池是一个我们经常要用到的概念。虽然在很多时候,我们都是用的第三方的数据库连接池,不需要我们亲自来做这个数据库连接池。但是,作为我们Java内部类使用的第一个场景,这个数据库连接池是一个很好的例子。为了简单起见,以下我们就来简单的模拟一下数据库连接池,在我们的例子中,我们只实现数据库连接池的一些简单的功能。如果想完全实现它,大家不妨自己试一试。
首先,我们定义一个接口,将数据库连接池的功能先定义出来,如下:



这是我们最最常用的一个JDBC编程的代码示例。一个系统有很多这样的查询方法,这段代码一般分作三段:try关键字括起来的那段是用来做查询操作的,catch关键字括起来的那段需要做两件事,记录出错的原因和事务回滚(如果需要的话),finally关键字括起来的那段用来释放数据库连接。
我们的烦恼是:try关键字括起来的那段是变化的,每个方法的一般都不一样。而catch和finally关键字括起来的那两段却一般都是不变的,每个方法的那两段都是一样的。既然后面那两段是一样的,我们就非常希望将它们提取出来,做一个单独的方法,然后让每一个使用到它们的方法调用。但是,try…catch…finally…是一个完整的语句段,不能把它们分开。这样的结果,使得我们不得不在每一个数据层方法里重复的写相同的catch…finally…这两段语句。
既然不能将那些讨厌的try…catch…finally…作为一个公用方法提出去,那么我们还是需要想其他的办法来解决这个问题。不然我们老是写那么重复代码,真是既繁琐,又不容易维护。
我们容易想到,既然catch…finally…这两段代码不能提出来,那么我们能不能将try…里面的代码提出去呢?唉哟,try…里面的代码是可变的呢。怎么办?
既然try…里面的代码是可变的,这意味着这些代码是可扩展的,是应该由用户来实现的,对于这样的可扩展内容,我们很容易想到用接口来定义它们,然后由用户去实现。这样以来我们首先定义一个接口:



这样,一个模板类就完成了。我们也通过这个模板类将catch…finally…两段代码提出来了。我们来看看使用了这个模板类的数据层方法是怎么实现的:


注意:本段代码仅供思路上的参考,没有经过上机测试。
我们可以看到,正是这个实现了DataManager接口得匿名内部类的使用,才使得我们解决了对try…catch…finally…语句的改造。这样,第一为我们解决了令人痛苦的重复代码;第二也让我们在数据层方法的编码中,直接关注对数据的操作,不用关心那些必需的但是与数据操作无关的东西。
我们现在来回想一下Spring框架的数据层,是不是正是使用了这种方法呢?


场景之三:一些多算法场合

假如我们有这样一个需求:我们的一个方法用来对数组排序并且依次打印各元素,对数组排序方法有很多种,用哪种方法排序交给用户自己确定。
对于这样一个需求,我们很容易解决。我们决定给哪些排序算法定义一个接口,具体的算法实现由用户自己完成,只要求他实现我们的接口就行。

在Arrays包里,对元素为对象的数组的排序:
the circle is drawing...the circle is erasing...the square is drawing...the square is erasing...the square is drawing...the square is erasing...the circle is drawing...the circle is erasing...

这个方法是巧妙地使用了内部类,将具体类的实现和它的具体工厂类绑定起来,由具体类的实现者在这个内部类的具体工厂里去产生一个具体类的对象,这当然容易得多。虽然需要每一个具体类都创建一个具体工厂类,但由于具体工厂类是一个内部类,这样也不会随着具体类的增加而不断增加新的工厂类,使得代码看起来很臃肿,这也是本方法不得不使用内部类的一个原因吧。

转自:http://blog.csdn.net/hivon/archive/2006/02/22/606312.aspx

读书人网 >编程

热点推荐