最近,看到有朋友在吐槽,说在用中间件的连接池的时候,得到的连接的实例,调用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,这种行为我们只能够用装饰器去实现增加接口方法的行为了。