最近,看到有朋友在吐槽,說在用中間件的連接池的時候,得到的連接的實例,調用close方法之後,不能回到池裏面,而是真的關閉了連接。爲什麼大家會覺得調用close方法是回到連接池而不是關閉連接呢?這個還要從最常見的JDBC的連接池說起,幾乎常見的jdbc的連接池在構造連接的時候都增強了connection類,將其close方法重寫爲returnPool之類的,調用關閉即可回去連接池。
class PoolConnection implements Connection {
Connection conn;
public PoolConnection(Connection conn,Pool<Connection> pool){
this.conn = conn;
}
...
@Override
public PreparedStatement prepareStatement(String sql) throws SQLException {
// TODO Auto-generated method stub
return conn.prepareStatement(sql);
}
@Override
public void close() throws SQLException {
//歸池
pool.returnObject(this);
}
}
可以看到,上述的增加的行爲是用裝飾器去實現的,這種實現,雖然會比較繁瑣(要實現接口所有的方法),好處也是顯而易見的,在沒有辦法手動初始化接口卻可以任意的在不改變接口的情況下,擴展我們的內部實現。回到最開始的,該中間件爲什麼調用close方法就沒有辦法close呢,很簡單,因爲它的連接池沒有針對該client的close方法去重寫或者是判斷是否是池化狀態。一般已經存在的中間件連接增加行爲的方式,又跟JDBC連接的有所不同,因爲我們知道怎麼去初始化一箇中間件的連接,且該連接只有一種實現(jdbc有多少種關係型數據庫就有多少種實現),所以,直接用繼承的方式就行了。
總結下,什麼情況下用裝飾器什麼情況下用繼承呢?其實很簡單。有且只有一種實現,並且我們知道如何構造的時候(至少看得懂源碼),我們就可以用繼承去擴展。反之,類似於IO、JDBC,這種行爲我們只能夠用裝飾器去實現增加接口方法的行爲了。