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