java内部类的四个应用场景Word文档格式.docx
《java内部类的四个应用场景Word文档格式.docx》由会员分享,可在线阅读,更多相关《java内部类的四个应用场景Word文档格式.docx(20页珍藏版)》请在冰豆网上搜索。
![java内部类的四个应用场景Word文档格式.docx](https://file1.bdocx.com/fileroot1/2022-12/7/1acddd39-cb64-4942-8eac-74eaa9dbcfd8/1acddd39-cb64-4942-8eac-74eaa9dbcfd81.gif)
init();
5.
//销毁连接池
6.
void
destory();
7.
//取得一个连接
8.
Connection
getConn();
9.
//还有一些其他的功能,这里不再列出
10.
……
11.}
publicinterfacePoolextendsTimerListener
{
//初始化连接池
publicbooleaninit();
//销毁连接池
publicvoiddestory();
//取得一个连接
publicConnectiongetConn();
//还有一些其他的功能,这里不再列出
……
}
有了这个功能接口,我们就可以在它的基础上实现数据库连接池的部分功能了。
我们首先想到这个数据库连接池类的操作对象应该是由Connection对象组成的一个数组,既然是数组,我们的池在取得Connection的时候,就要对数组元素进行遍历,看看Connection对象是否已经被使用,所以数组里每一个Connection对象都要有一个使用标志。
我们再对连接池的功能进行分析,会发现每一个Connection对象还要一个上次访问时间和使用次数。
通过上面的分析,我们可以得出,连接池里的数组的元素应该是由对象组成,该对象的类可能如下:
class
PoolConn
private
conn;
isUse;
long
lastAccess;
int
useCount;
8.}
publicclassPoolConn
privateConnectionconn;
privatebooleanisUse;
privatelonglastAccess;
privateintuseCount;
下面的省略号省掉的是关于四个属性的一些get和set方法。
我们可以看到这个类的核心就是Connection,其他的一些属性都是Connection的一些标志。
可以说这个类只有在连接池这个类里有用,其他地方用不到。
这时候,我们就该考虑是不是可以把这个类作为一个内部类呢?
而且我们把它作为一个内部类以后,可以把它定义成一个私有类,然后将它的属性公开,这样省掉了那些无谓的get和set方法。
下面我们就试试看:
ConnectPool
implements
Pool
//存在Connection的数组
PoolConn[]
poolConns;
//连接池的最小连接数
min;
//连接池的最大连接数
max;
//一个连接的最大使用次数
maxUseCount;
11.
//一个连接的最大空闲时间
12.
maxTimeout;
13.
//同一时间的Connection最大使用个数
14.
maxConns;
15.
//定时器
16.
Timer
timer;
17.
init()
18.
{
19.
try
20.
21.
22.
this.poolConns
=
new
PoolConn[this.min];
23.
for(int
i=0;
i<
this.min;
i++)
24.
25.
PoolConn
poolConn
PoolConn();
26.
poolConn.conn
ConnectionManager.getConnection();
27.
poolConn.isUse
false;
28.
poolConn.lastAccess
Date().getTime();
29.
poolConn.useCount
0;
30.
this.poolConns[i]
poolConn;
31.}
32.……
33.return
true;
34.
}
35.
catch(Exception
e)
36.
37.
return
38.}
39.}
40.……
41.private
42.{
43.
44.
45.public
46.
47.}
48.}
publicclassConnectPoolimplementsPool
//存在Connection的数组
privatePoolConn[]poolConns;
//连接池的最小连接数
privateintmin;
//连接池的最大连接数
privateintmax;
//一个连接的最大使用次数
privateintmaxUseCount;
//一个连接的最大空闲时间
privatelongmaxTimeout;
//同一时间的Connection最大使用个数
privateintmaxConns;
//定时器
privateTimertimer;
publicbooleaninit()
{
try
this.poolConns=newPoolConn[this.min];
for(inti=0;
i++)
PoolConnpoolConn=newPoolConn();
poolConn.conn=ConnectionManager.getConnection();
poolConn.isUse=false;
poolConn.lastAccess=newDate().getTime();
poolConn.useCount=0;
this.poolConns[i]=poolConn;
……
returntrue;
}
catch(Exceptione)
returnfalse;
privateclassPoolConn
publicConnectionconn;
publicbooleanisUse;
publiclonglastAccess;
publicintuseCount;
因为本文不是专题来讲述数据库连接池的,所以在上面的代码中绝大部分的内容被省略掉了。
PoolConn类不大可能被除了ConnectionPool类的其他类使用到,把它作为ConnectionPool的私有内部类不会影响到其他类。
同时,我们可以看到,使用了内部类,使得我们可以将该内部类的数据公开,ConnectionPool类可以直接操作PoolConn类的数据成员,避免了因set和get方法带来的麻烦。
上面的一个例子,是使用内部类使得你的代码得到简化和方便。
还有些情况下,你可能要避免你的类被除了它的外部类以外的类使用到,这时候你却不得不使用内部类来解决问题。
场景二:
解决一些非面向对象的语句块
这些语句块包括if…elseif…else语句,case语句,等等。
这些语句都不是面向对象的,给我们造成了系统的扩展上的麻烦。
我们可以看看,在模式中,有多少模式是用来解决由if语句带来的扩展性的问题。
Java编程中还有一个困扰我们的问题,那就是try…catch…问题,特别是在JDBC编程过程中。
请看下面的代码:
1.try
2.
String[]
divisionData
null;
conn
manager.getInstance().getConnection();
stmt
(OracleCallableStatement)conn.prepareCall("
{
Call
PM_GET_PRODUCT.HEADER_DIVISION(?
?
)
}"
);
stmt.setLong(1
productId.longValue()
stmt.registerOutParameter(2,
oracle.jdbc.OracleTypes.CURSOR);
;
stmt.execute();
ResultSet
rs
stmt.getCursor
(2);
i
0
String
strDivision
"
while(
rs.next()
)
+=
rs.getString("
DIVISION_ID"
+
"
length
strDivision.length()
if(length
!
strDivision.substring(0,length
-
1);
StringUtil.split(strDivision,
map.put("
Division"
LoggerAgent.debug("
GetHeaderProcess"
getDivisionData"
getValue
+"
productId)
}catch(Exception
LoggerAgent.error("
GetHeaderData"
SQLException:
e);
e.printStackTrace()
}finally
31.
32.
manager.close(stmt);
33.
manager.releaseConnection(conn);
}
try
String[]divisionData=null;
conn=manager.getInstance().getConnection();
stmt=(OracleCallableStatement)conn.prepareCall("
{CallPM_GET_PRODUCT.HEADER_DIVISION(?
?
)}"
stmt.setLong(1,productId.longValue());
stmt.registerOutParameter(2,oracle.jdbc.OracleTypes.CURSOR);
;
stmt.execute();
ResultSetrs=stmt.getCursor
(2);
inti=0;
StringstrDivision="
while(rs.next())
strDivision+=rs.getString("
)+"
intlength=strDivision.length();
if(length!
=0)
strDivision=strDivision.substring(0,length-1);
divisionData=StringUtil.split(strDivision,"
);
map.put("
strDivision);
LoggerAgent.debug("
getValue+"
+strDivision+"
"
+productId);
}catch(Exceptione)
LoggerAgent.error("
"
+e);
e.printStackTrace();
}finally
manager.close(stmt);
manager.releaseConnection(conn);
这是我们最最常用的一个JDBC编程的代码示例。
一个系统有很多这样的查询方法,这段代码一般分作三段:
try关键字括起来的那段是用来做查询操作的,catch关键字括起来的那段需要做两件事,记录出错的原因和事务回滚(如果需要的话),finally关键字括起来的那段用来释放数据库连接。
我们的烦恼是:
try关键字括起来的那段是变化的,每个方法的一般都不一样。
而catch和finally关键字括起来的那两段却一般都是不变的,每个方法的那两段都是一样的。
既然后面那两段是一样的,我们就非常希望将它们提取出来,做一个单独的方法,然后让每一个使用到它们的方法调用。
但是,try…catch…finally…是一个完整的语句段,不能把它们分开。
这样的结果,使得我们不得不在每一个数据层方法里重复的写相同的catch…finally…这两段语句。
既然不能将那些讨厌的try…catch…finally…作为一个公用方法提出去,那么我们还是需要想其他的办法来解决这个问题。
不然我们老是写那么重复代码,真是既繁琐,又不容易维护。
我们容易想到,既然catch…finally…这两段代码不能提出来,那么我们能不能将try…里面的代码提出去呢?
唉哟,try…里面的代码是可变的呢。
怎么办?
既然try…里面的代码是可变的,这意味着这些代码是可扩展的,是应该由用户来实现的,对于这样的可扩展内容,我们很容易想到用接口来定义它们,然后由用户去实现。
这样以来我们首先定义一个接口:
DataManager
manageData();
4.}
publicinterfaceDataManager
publicvoidmanageData();
我们需要用户在manageData()方法中实现他们对数据层访问的代码,也就是try…里面的代码。
然后我们使用一个模板类来实现所有的try…catch…finally…语句的功能,如下:
publicclassDataTemplate
{
publicvoidexecute(DataManagerdm)
{
try
dm.manageData();
}
catch(Exceptione)
}finally
这样,一个模板类就完成了。
我们也通过这个模板类将catch…finally…两段代码提出来了。
我们来看看使用了这个模板类的数据层方法是怎么实现的:
newDataTemplate().execute(newDataManager()
publicvoidmanageData()
while(rs.next())