分享程序网
首页
  • java
微服务
微前端
环境搭建
数据库
设计模式
算法
软件
解决问题
链接
首页
  • java
微服务
微前端
环境搭建
数据库
设计模式
算法
软件
解决问题
链接
  • 创建模式

    • 单例模式
    • 工厂方法模式
    • 抽象工厂模式
    • 原型模式
    • 建造者模式
  • 结构模式

    • 适配器模式
    • 桥接模式
    • 组合模式
    • 装饰器模式
    • 门面模式
    • 享元模式
    • 代理模式
  • 行为模式

    • 责任链模式
    • 命令模式
    • 迭代器模式
    • 策略模式
    • 模板方法模式

抽象工厂模式

使用抽象工厂模式创建数据库连接池

抽象类

package com.design.factorymethod.abstractfactory;

import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties;

/**
 * 自定义连接池getInstance()返回POOL唯一实例,第一次调用时将执行构造函数
 *  构造函数Pool()调用驱动装载loadDrivers()函数
 * 连接池创建createPool()函数,loadDrivers()装载驱动
 * createPool创建连接池,getConnection()返回一个连接实例
 * getConnection(long time)添加时间限制 
 * freeConnection(Connection conn) 将conn连接实例返回连接池,
 * getnum()返回空闲连接数 
 * getNumActive()返回当前使用的连接数
 */
public abstract class Pool {
	
	private String propertiesName = "db.properties";

	/**
	 * 定义唯一实例
	 */
	private static Pool instance = null;

	/**
	 * 最大连接数
	 */
	protected int maxConnect = 100;

	/**
	 * 保持连接数
	 */
	protected int normalConnect = 10;

	/**
	 * 驱动字符串
	 */
	protected String driverName = null;

	/**
	 * 驱动类
	 */
	protected Driver driver = null;

	/**
	 * 私有构造,不允许外界访问
	 */
	protected Pool() {
		try {
			init();
			loadDrivers(driverName);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * 初始化所有从配置文件中读取的成员变量
	 */
	private void init() throws IOException {
		InputStream is = Pool.class.getResourceAsStream(propertiesName);
		Properties properties = new Properties();
		properties.load(is);
		this.driverName = properties.getProperty("driverName");
		this.maxConnect = Integer.parseInt(properties.getProperty("db.maxConnect"));
		this.normalConnect = Integer.parseInt(properties.getProperty("db.normalConnect"));
	}

	/**
	 * 装载和注册所有JDBC驱动程序
	 *
	 * @param driverName 接受驱动字符串
	 */
	protected void loadDrivers(String driverName) {
		try {
			Class.forName(driverName);
			System.out.println("成功注册JDBC驱动程序" + driverName);
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
			System.out.println("无法注册JDBC驱动程序:" + driverName + ",错误:" + e);
		}
	}

	/**
	 * 创建连接池
	 */
	public abstract void createPool() throws IOException;

	/**
	 * (单例模式)返回数据库连接池Pool的实例
	 */
	public static synchronized Pool getInstance()
			throws ClassNotFoundException, IllegalAccessException, InstantiationException, IOException {
		if (instance == null) {
			instance = (Pool) Class.forName("").newInstance();
		}
		return instance;
	}

	/**
	 * 获取一个可用的连接,如果没有,则创建一个连接,并且小于最大连接限制
	 */
	public abstract Connection getConnection();

	/**
	 * 获取一个连接,有时间限制
	 *
	 * @param time 设置该连接的持续时间(单位:毫秒)
	 * @return 返回连接对象
	 */
	public abstract Connection getConnection(long timeout);

	/**
	 * 将连接对象返回连接池
	 * 
	 * @param conn 获得的连接对象
	 */
	public abstract void freeConnection(Connection conn);

	/**
	 * 返回当前空闲的连接数
	 *
	 * @return 空闲连接数
	 */
	public abstract int getNum();

	/**
	 * 返回当前工作的连接数
	 */
	public abstract int getNumActive();

	protected synchronized void release() {
		try {
			DriverManager.deregisterDriver(driver);
			System.out.println("撤销JDBC驱动程序" + driver.getClass().getName());
		} catch (SQLException throwables) {
			throwables.printStackTrace();
			System.out.println("无法撤销JDBC驱动程序的注册:" + driver.getClass().getName());
		}
	}
}

数据库连接池

package com.design.factorymethod.abstractfactory;

import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Enumeration;
import java.util.Properties;
import java.util.Vector;

/**
 * 数据库连接池管理类
 */
public final class DBConnectionPool extends Pool {
	/**
	 * 正在使用的连接数
	 */
	private int checkedOut;

	/**
	 * 存放产生的连接对象容器
	 */
	private Vector<Connection> freeConnections = new Vector<>();

	/**
	 * 密码
	 */
	private String password = null;

	/**
	 * 连接字符串
	 */
	private String url = null;

	/**
	 * 用户名
	 */
	private String userName = null;

	/**
	 * 空闲连接数
	 */
	private static int num = 0;

	/**
	 * 当前可用的连接数
	 */
	private static int numActive = 0;

	/**
	 * 连接池实例变量
	 */
	private static DBConnectionPool pool = null;

	/**
	 * 产生数据连接池
	 *
	 * @return
	 */
	public static synchronized DBConnectionPool getInstance() throws IOException {
		if (pool == null) {
			pool = new DBConnectionPool();
		}
		return pool;
	}

	/**
	 * 获得一个数据库连接池的实例
	 */
	private DBConnectionPool() throws IOException {
		init();
		// 初始normal个连接
		for (int i = 0; i < normalConnect; i++) {
			Connection conn = newConnection();
			if (conn != null) {
				// 往容器中添加一个连接对象
				freeConnections.addElement(conn);
				// 记录总连接数
				num++;
			}
		}
	}

	/**
	 * 初始化
	 *
	 * @throws IOException
	 */
	private void init() throws IOException {
		InputStream is = DBConnectionPool.class.getResourceAsStream("db.properties");
		Properties properties = new Properties();
		properties.load(is);
		this.userName = properties.getProperty("db.username");
		this.password = properties.getProperty("db.password");
		this.driverName = properties.getProperty("db.driver");
		this.url = properties.getProperty("db.url");
		this.maxConnect = Integer.parseInt(properties.getProperty("db.maxConnect"));
		this.normalConnect = Integer.parseInt(properties.getProperty("db.normalConnect"));
	}

	/**
	 * 如果不再使用某个连接对象,则可调此方法将该对象释放到连接池
	 */
	@Override
	public synchronized void freeConnection(Connection conn) {
		freeConnections.addElement(conn);
		num++;
		checkedOut--;
		numActive--;
		// 解锁
		notifyAll();
	}

	private Connection newConnection() {
		Connection conn = null;
		try {
			// 用户名为空
			if (userName == null) {
				conn = DriverManager.getConnection(this.url);
			} else {
				conn = DriverManager.getConnection(this.url, this.userName, this.password);
			}
			System.out.println("连接池创建一个新的连接");
		} catch (SQLException throwables) {
			throwables.printStackTrace();
			System.out.println("无法创建这个URL的连接" + this.url);
			return null;
		}
		return conn;
	}

	/**
	 * 获取一个可用连接(单例模式)
	 *
	 * @return
	 */
	@Override
	public synchronized Connection getConnection() {
		Connection conn = null;
		// 还有空闲的连接
		if (freeConnections.size() > 0) {
			num--;
			conn = freeConnections.firstElement();
			freeConnections.removeElement(0);
			try {
				if (conn.isClosed()) {
					System.out.println("从连接池删除一个无效连接");
					conn = getConnection();
				}
			} catch (SQLException throwables) {
				throwables.printStackTrace();
				System.out.println("从连接池删除一个无效连接");
				conn = getConnection();
			}
			// 没有空闲连接且当前连接小于最大允许值,若最大值为0,则不限制
		} else if (maxConnect == 0 || checkedOut < maxConnect) {
			conn = newConnection();
		}
		if (conn != null) {
			checkedOut++;
		}
		numActive++;
		return conn;
	}

	/**
	 * 获取一个连接,并加上等待时间限制,时间为毫秒
	 *
	 * @param timeout 设置该连接的持续时间(单位:毫秒)
	 * @return
	 */
	@Override
	public synchronized Connection getConnection(long timeout) {
		long startTime = System.currentTimeMillis();
		Connection conn;
		while ((conn = getConnection()) == null) {
			try {
				wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			if ((System.currentTimeMillis() - startTime >= timeout)) {
				return null;
			}
		}
		return conn;
	}

	@Override
	public int getNum() {
		return DBConnectionPool.num;
	}

	@Override
	public int getNumActive() {
		return DBConnectionPool.numActive;
	}

	/**
	 * 关闭所有连接
	 */
	@Override
	protected synchronized void release() {
		try {
			// 将当前连接赋值到枚举中
			Enumeration<Connection> allConnections = freeConnections.elements();
			// 使用循环关闭连接池中的所有连接
			while (allConnections.hasMoreElements()) {
				// 如果此枚举对象至少还有一个可提供的元素,则返回此枚举的下一个元素
				Connection conn = allConnections.nextElement();
				conn.close();
				num--;
			}
			freeConnections.removeAllElements();
			numActive = 0;
		} catch (SQLException throwables) {
			throwables.printStackTrace();
		} finally {
			super.release();
		}
	}

	@Override
	public void createPool() throws IOException {
		pool = new DBConnectionPool();
		if (pool != null) {
			System.out.println("创建连接池成功");
		} else {
			System.out.println("创建连接池失败");
		}
	}
}

使用

public static void main(String[] args) throws SQLException, IOException {
    DBConnectionPool connectionPool = DBConnectionPool.getInstance();
    //创建连接池
    connectionPool.createPool();
    String sql = "select * from user";
    Connection connection = connectionPool.getConnection();
    PreparedStatement preparedStatement = connection.prepareStatement(sql);
    ResultSet resultSet = preparedStatement.executeQuery();
    System.out.println(resultSet);
    //关闭所有链接
    connectionPool.release();
}

工厂方法模式和抽象工厂模式的区别

工厂方法模式只能单向维度的扩展,而抽象工厂模式都是多向维度的。再之前工厂方法模式中,换一个思维,写一个抽象类,抽象类中把每个算法的对象创建交给方法,那么就相当于抽象工厂模式了。如果又多出一个排序算法呢?那么抽象工厂模式并不适用,修改太大,因为没有创建这个算法对象的接口方法或者抽象方法。如果是除了排序,还有倒序,获取最大值的算法呢?那么使用抽象工厂模式就可以。创建一个有获取最大值的抽象方法,所有算法对象实现继承该抽象方法即可。

Last Updated:
Contributors: chengli, clcheng
Prev
工厂方法模式
Next
原型模式