從一個ConnectionPool的實現看design pattern的運用 (五) (轉)

worldblog發表於2007-12-13
從一個ConnectionPool的實現看design pattern的運用 (五) (轉)[@more@]

從一個ConnectionPool的實現看design pattern的運用 ():namespace prefix = o ns = "urn:schemas--com::office" />

OK, 現在我們已經把封裝Connection的任務從ConnectionPool的開發者身上去掉了。他們只要實現一個輔助的ConnectionMan 介面,餘下的事由PooledConnection類和ConnectionMan2ConnectionPool類來完成。

 

下面,再讓我們仔細地看一下ConnectionManImpl類:

public class ConnectioManImpl implements ConnectionMan{

public synchronized Connection getConnection(){

  Connection ret;

    如果pool裡有Connection

從pool中去掉一個Connection conn;

clients++;

ret = conn;

    否則,如果clients

    conn = newConnection();

    clients++;

    ret = conn;

    否則,wait(),直到pool中有空閒Connection 

return conn;

  }

  public synchronized void closeConnection(Connection conn){

    pool.add(conn);

    clients--;

    notify();

}

private Connection newConnection(){

//使用名,密碼,url等等資訊從Manager生成一個Connection

}

//必要的一些使用者名稱,密碼等建立connection的資訊。

}

 

大家是否注意到了?ConnectionMan的實現者除了寫pooling的演算法,還要關心如何建立connection. 而這個建立connection的過程並不是總是一樣的。我們可能從DriverManager生成Connection, 也可能從Data生成connection;可能用使用者名稱,密碼生成,也可能用connection string生成。

同樣的pooling邏輯,可能需要處理不同的生成Connection的方式, 同一種生成connection的方式又有可能需要不同的pooling邏輯。因此,把pooling邏輯和connection生成耦合在一起似乎不是一個好辦法。

 

那麼如何解決這個問題呢?pooling演算法中,確實需要在適當的時刻生成connection啊!

 

“把ConnectionManImpl做成抽象類,然後要求每個子類覆蓋newConnection()方法”。 資深員張三不屑地說。

 

是啊,這確實是個直觀又有效的方法。對同一個pooling演算法,你只要subclass自己的子類,制定自己的connection生成,就可以重用父類的邏輯。這叫template method pattern.

 

不過,說實話,個人很不喜歡這個pattern. 從此例來說,假如我們有五種pooling演算法,三種connection生成方法,那我們就需要寫十五個子類。太不靈活了。而且,實現繼承造成的父子類的強耦合關係,也是我所向來討厭的。父類的某個不經心的改變,有可能就使子類不再工作。

 

那麼。。。。

 

對啦!讓我們抽象一下connection的生成吧。用abstract factory.

 

先定義一個factory的介面。

public interface ConnectionFactory{

  public Connection createConnection()throws Exception;

}

然後改寫我們的ConnectionManImpl, 讓它把生成Connection的工作委託給一個ConnectionFactory.

 

Public class ConnectionManImpl implements ConnectionMan{

  Private final ConnectionFactory factory;

  Private final int maxConn;

  private ConnectionManImpl(ConnectionFactory factory, int max){

    this.factory = factory;

    this.maxConn = max;

  }

  static public ConnectionMan instance(ConnectionFactory factory, int max){

    return new ConnectionManImpl(factory, max);

  }

  public final synchronized Connection getConnection()

  throws SQLException

  {

    如果pool裡有Connection

從pool中去掉一個Connection conn;

clients++;

return conn;

    否則,如果clients

    conn = factory.createConnection();

    clients++;

    return conn;

    否則,wait(),直到pool中有空閒Connection 

  }

  //其他和前面一樣。

}

 

再看一個示例ConnectionFactory的實現:

public class ConnectionFactoryImpl

{

  private ConnectionFactoryImpl(){}

  static public ConnectionFactory instance(final String user, final String pwd,

    final String url, final String driver)

  throws SQLException, ClassNotFoundException{

    final Class driverClass = Class.forName(driver);

    return new ConnectionFactory(){

      private final Class keeper = driverClass;

      public final Connection createConnection()

      throws SQLException{

      return DriverManager.getConnection(url,user,pwd);

    }

    };

  } 

}

 

最後,再看看我們是怎樣把一個ConnectionMan, 一個ConnectionFactory組合成一個ConnectionPool的。

 

public class TestConnectionPool{

  public static void test(String user, String pwd, String url, String driver)

  throws .sql.SQLException, ClassNotFoundException{

    final ConnectionPool pool = ConnectionMan2ConnectionPool.decorate(

    ConnectionManImpl.instance(

      ConnectionFactoryImpl.instance(user, pwd, url, driver),

      1000)

    );

  }

}

 

 

好啦,這一章,我們顯示了怎樣把ConnectionManImpl中的pooling邏輯和Connection 生成的邏輯分開,從而實現更大程度上的程式碼重用。

 

思考題:

pooling, 作為一種技術,並不只是應用於ConnectionPool, 其他如Thread pool以及任何一種需要一定開銷建立的資源都可以應用這種技術。

那麼,我們怎樣能夠把一個pooling的演算法重用給connection pool, thread pool等不同的pool呢?怎樣才能說:“給我李四寫的pooling演算法,我要拿它來對我的執行緒進行緩衝。”?而不是說:“李四,你的connection pooling演算法寫的不錯,能不能給我的thread pooling也寫一個一樣的?”

 


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-992488/,如需轉載,請註明出處,否則將追究法律責任。

相關文章