设计模式-享元模式

发布于:2024-07-02 ⋅ 阅读:(7) ⋅ 点赞:(0)

一、享元模式的核心思想–共享

享元的英文是 Flyweight,它是一个来自于体育方面的专业用语,在拳击、摔跤和举重比赛中特指最轻量的级别。把这个单词移植到软件工程里面,也是用来表示特别小的对象,即细粒度对象。Flyweight享元,可以理解为共享元对象,也就是共享细粒度对象。享元模式就是通过使用共享的方式,达到高效地支持大量的细粒度对象。它的目的就是节省占用的空间资源,从而实现系统性能得到改善。

享元模式主要作用是实现对象的共享,即使用共享池,从而减少内存分配的开销。享元模式通常与工厂模式一起使用,它包含了多个共享的组合对象,因此:享元模式=单例模式+工厂模式+合成模式,其结构如图下所示。

在这里插入图片描述
其中:FlyweightFactoiy享元工厂负责创建和管理享元对象,它必须保证享元对象可以被系统适当共享。当一个客户端对象请求一个享元对象的时候,享元工厂需要检查系统中是否已经有一个符合要求的享元对象,如果已经有了,享元工厂就应当提供这个已有的享元对象;如果系统中没有一个适当的享元对象的话,享元工厂就应当创建一个新的合适的享元对象。Flyweight是所有的具体享元类的超类,为这些类规定出需要实现的公共接口或抽象类。MyFlyweight1和MyFlyweight2 则是实现抽象享元所规定的接口。

二、何时使用享元模式

在程序设计中会出现这样的情况:看起来似乎需要大量细粒度的类实例来表示数据。如果能发现这些实例除了几个参数外基本都是相同的,有时就能够大幅度地减少需要实例化的类的数量。如果能把那些参数移到类实例外面,在方法调用时将它们传递进来,就可以通过共享大幅度地减少单个实例的数目。如果从类中移出某些数据并存储到外部,且这样能大幅度地减少程序需要保存的不同类实例的数量,就适合使用享元模式,以避免大量非常相似的类的开销。

享元模式只是用几个对象实例表示程序中的多个不同对象,这些实例通常把相同的基本属性作为内部数据,把少数几个属性作为外部数据,它们通常随类实例表现形式不同而不同。

三、Java 中的应用–数据库连接池

享元模式由于其共享特性,可以使用在任何池化的操作中,如线程池、数据库连接池等。数据库连接池是享元模式的一个典型应用。在该应用中,需要一个连接池工厂类ConnectPool,它是多个连接 Connection 的聚集,其结构如下图所示。

在这里插入图片描述
连接池工厂类 ConnectPool具有一个数据集合对象 pool,它在构造函数中进行初始化。该类提供了一个单例的工厂类,以防止重复创建该工厂实例,并提供取得连接getConnection()和释放连接freeConnection()函数来分别从共享池中取得和释放一个连接。

其源代码如下程序所示。

package structure.flyweight;


import java.sql.Connection;
import java.sql.SOLException;
import java.util.Veetor;


/**
* @author Minggg
* 享元模式-连接池实例
*/
public class ConnectionPool {

	private Vector<Connection> pool;
	private String url = "jdbc:mysql://localhost:3306/test";
	private String username = "root" ;
	private String password = "123456";
	private String driverClassName = "com.mysql.jdbc.Driver";
	
	//连接池的大小,也就是连接池中有多少个数据库连接
	private int poolSize = 100;
	private static ConnectionPool instance = null;
	
	/**
	* 私有的构造方法,禁止外部创建本类的对象,要想获得本类的对象,通过<code>getlstale</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 getInstanee() {
		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,然后使用getConnection0来取得一个连接执行 SOL 查询,最后使用freeConnection()来释放连接即可。其源代码如下程序所示。

package structure.flyweigh;


import java.sal.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 (inti= 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(eonn);
		}
		pool.closePool();
	}
}

通过以上连接池的管理,实现了数据库连接的共享,不需要每一次取得连接时都重新创建,因为节省了重复创建数据库连接的开销,使得程序的性能大幅提升。