享元模式是对象的结构模式。享元模式以共享的方式高效地支持大量的细粒度对象。
单纯享元模式所涉及到的角色如下:
● 抽象享元(Flyweight)角色 :给出一个抽象接口,以规定出所有具体享元角色需要实现的方法。
● 具体享元(ConcreteFlyweight)角色:实现抽象享元角色所规定出的接口。如果有内蕴状态的话,必须负责为内蕴状态提供存储空间。
● 享元工厂(FlyweightFactory)角色 :本角色负责创建和管理享元角色。本角色必须保证享元对象可以被系统适当地共享。当一个客户端对象调用一个享元对象的时候,享元工厂角色会检查系统中是否已经有一个符合要求的享元对象。如果已经有了,享元工厂角色就应当提供这个已有的享元对象;如果系统中没有一个适当的享元对象的话,享元工厂角色就应当创建一个合适的享元对象。
享元模式由于其共享特性,可以使用在任何池化的操作中,如线程池、数据库连接池等。数据库连接池是享元模式的一个典型应用。在该应用中,需要一个连接池工厂类ConnectPool,它是多个连接Connection的聚集,其结构如图12-26所示。
连接池工厂类ConnectPool具有一个数据集合对象pool,它在构造函数中进行初始化。该类提供了一个单例的工厂类,以防止重复创建该工厂实例,并提供取得连接getConnection()和释放连接freeConnection()函数来分别从共享池中取得和释放一个连接。
其源代码如程序12-47所示。
程序12-47 连接池实例ConnectionPool.java
- package structure.flyweight;
- import java.sql.Connection;
- import java.sql.SQLException;
- import java.util.Vector;
- /**
- * @author liuzhongbing
- * 享元模式-连接池实例
- */
- public class ConnectionPool {
- private Vector<Connection> pool;
- private String url = "jdbc:mysql://localhost:3306/test";
- private String username = "root";
- private String password = "";
- private String driverClassName = "com.mysql.jdbc.Driver";
- /**
- * 连接池的大小,也就是连接池中有多少个数据库连接
- */
- private int poolSize = 100;
- private static ConnectionPool instance = null;
- /**
- * 私有的构造方法,禁止外部创建本类的对象,要想获得本类的对象,
- 通过<code>getIstance</code>方法
- * 使用了设计模式中的单子模式
- */
- private ConnectionPool() {
- pool = new Vector<Connection>(poolSize);
- // 在连接池中创建初始设置的数据库连接
- Connection conn = null;
- for (int i = 0; i < poolSize; i++) {
- try {
- Class.forName(driverClassName);
- conn = java.sql.DriverManager.getConnection(url,
- username, password);
- pool.add(conn);
- } catch (ClassNotFoundException e) {
- e.printStackTrace();
- } catch (SQLException e) {
- e.printStackTrace();
- }
- }
- }
- /**
- * 返回连接到连接池中
- */
- public synchronized void release(Connection conn) {
- pool.add(conn);
- }
- /**
- * 关闭连接池中的所有数据库连接
- */
- public synchronized void closePool() {
- for (int i = 0; i < pool.size(); i++) {
- try {
- ((Connection) pool.get(i)).close();
- } catch (SQLException e) {
- e.printStackTrace();
- }
- pool.remove(i);
- }
- }
- /**
- * 返回当前连接池的一个对象
- */
- public static ConnectionPool getInstance() {
- if (instance == null) {
- instance = new ConnectionPool();
- }
- return instance;
- }
- /**
- * 返回连接池中的一个数据库连接
- */
- public synchronized Connection getConnection() {
- if (pool.size() > 0) {
- Connection conn = pool.get(0);
- pool.remove(conn);
- return conn;
- } else {
- return null;
- }
- }
- }
要使用该连接池,只需要创建一个连接池的实例pool,然后使用getConnection()来取得一个连接执行SQL查询,最后使用freeConnection()来释放连接即可。其源代码如程序12-48所示。
程序12-48 连接池测试类ConnectionPoolTest.java
- package structure.flyweight;
- import java.sql.Connection;
- import java.sql.ResultSet;
- import java.sql.Statement;
- public class ConnectionPoolTest {
- public static void main(String[] args) throws Exception {
- String sql = "select id,name,phone from guestmessage";
- ConnectionPool pool = ConnectionPool.getInstance();
- for (int i = 0; i < 100; i++) {
- Connection conn = pool.getConnection();
- Statement stmt = conn.createStatement();
- ResultSet rs = stmt.executeQuery(sql);
- while (rs.next()) {
- }
- rs.close();
- stmt.close();
- pool.release(conn);
- }
- pool.closePool();
- }
- }
通过以上连接池的管理,实现了数据库连接的共享,不需要每一次取得连接时都重新创建,因为节省了重复创建数据库连接的开销,使得程序的性能大幅提升。