二、裝飾模式
2.1 裝飾模式原理Connection close
目的:改寫已存在的類的某個方法或某些方法,裝飾設(shè)計模式(包裝模式)
口訣:
1、編寫一個類,實現(xiàn)與被包裝類相同的接口。(具備相同的行為)
2、定義一個被包裝類類型的成員變量。
3、定義構(gòu)造方法,把被包裝類的對象注入,給被包裝類變量賦值。
4、對于不需要改寫的方法,調(diào)用原有的方法。
5、對于需要改寫的方法,寫自己的代碼。
1.包裝Connection的實現(xiàn)類
//mysql的Connection類實現(xiàn)了sun公司的Connection的接口規(guī)范
//我們要包裝的是mysql的Connection
//所以:我們寫的這個包裝類也要實現(xiàn)sun公司的Connection的接口規(guī)范--我們的類與mysql的Connection要具有相同的約束動作
//1.編寫一個類,使之與被包裝類實現(xiàn)相同的接口(具有相同的行為)
public class DecoratorConnection implements Connection{
private Connection oldConnection; //2.添加一個被包裝類的對象(依賴的關(guān)系)--實際上運行的時候傳過來的是實現(xiàn)類的對象:com.mysql.jdbc.Connection的實例
private LinkedList<Connection> pool;
//3.定義構(gòu)造方法,通過構(gòu)造方法的參數(shù),將被包裝類注入,給被包裝類賦值
//實際上運行的時候傳過來的是實現(xiàn)類的對象:com.mysql.jdbc.Connection的實例
public DecoratorConnection(Connection conn,LinkedList<Connection> pool){
this.oldConnection = conn;
this.pool = pool;
}
//5.需要改寫的方法:自己寫代碼
@Override
public void close() throws SQLException {
//因為這里關(guān)閉連接也需要連接池的引用,所以,也必須把連接池注入到本類中
pool.addLast(oldConnection);
}
//下面的方法不需要改變原有的功能,只以prepareStatement(String sql)為例,以下其它方法相同:
//4.對于不需要改寫的方法,調(diào)用原有的方法
@Override
public PreparedStatement prepareStatement(String sql) throws SQLException {
return oldConnection.prepareStatement(sql);
}
//其它方法略……
}
2.連接池產(chǎn)生的Connection是被包裝之后的類
//sun公司開發(fā)一套連接池的接口規(guī)范DataSource,自定義的連接池,要實現(xiàn)這個規(guī)范
//這回實現(xiàn)連接池,使用的是實現(xiàn)sun公司的接口
public class MyDataSource implements DataSource{
// 創(chuàng)建一個連接的池子--集合,線程安全的問題
private static LinkedList<Connection> pool = (LinkedList<Connection>) Collections
.synchronizedList(new LinkedList<Connection>());
// 在連接池中初始化10個連接
static {
try {
for (int i = 0; i < 10; i++) {
Connection conn = DBUtil.getConnection();
pool.add(conn);
}
} catch (Exception e) {
// 將異常向上拋
throw new ExceptionInInitializerError("初始化連接池失??!");
}
}
// 重寫getConnection()方法
@Override
public Connection getConnection() throws SQLException {
Connection conn = null;
if(pool.size()>0){ //說明池子里還有連接
conn = pool.removeFirst(); //移除并返回對象
Connection myConn = new DecoratorConnection(conn,pool); //得到一個包裝后的Connection對象
return myConn; //返回的是包裝之后的Connection
}else{
throw new RuntimeException("服務(wù)器正忙.......");
//服務(wù)器正忙的解決思路:
//1.等待
//2.等待超時新創(chuàng)建一個連接用DBUtil產(chǎn)生,用完之后,不用交回池,真的close()
}
}
// 其余方法實現(xiàn)……
@Override
public PrintWriter getLogWriter() throws SQLException {
// TODO Auto-generated method stub
return null;
}
3.編寫測試類
public static void main(String[] args) {
Connection conn = null;
PreparedStatement ps = null;
try {
DataSource ds = new MyDataSource();
conn = ds.getConnection(); //從池中取出一個連接,這個連接已經(jīng)被包裝了DecoratorConnection類型的
ps = conn.prepareStatement(".........");
ps.executeQuery();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
try {
conn.close(); //調(diào)用了包裝Connection之后的DecoratorConnection的close()方法了
//即:被連接池回收了
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}