2.0 - The Three Musketeers design patterns factory pattern - abstract factory pattern

Abstract Factory (Abastract Factory Pattern) provide a means to create a series of related or dependent objects interface, without specifying their concrete classes. The client (application layer) does not depend on how the product class instance is created, realized and other details, the emphasis is to create objects to use requires a lot of repetitive code with a series of related product objects (belonging to the same product family). Need to provide a product class library, all of the products appear in the same interface, so that the client does not depend on the specific implementation. Explaining the abstract factory, we have to understand two concepts of product hierarchy and product family, see the following chart:

 

Seen from the figure above a square, circle, and diamond three types of graphics, shades of the same color represents the same product family, representing the same shape, the same product a hierarchical structure. The same can be, for example from life, for example, the US electrical production of a variety of household appliances. So the figure above, the darkest square on behalf of the United States and the washing machine, the darkest circles represent the US air darkest diamonds represent US water heater, the deepest color in a row all brands belong to the United States, are Midea this product family. Look at the far right of the diamond, we specify the color of the deepest water heater representative of the United States, then the second row of a lighter color a little diamond, on behalf of Hisense water heater. Similarly, the same product mix as well as Gree water heater, Gree air-conditioning, Gree washing machine

 

Look at this chart below, the left-most small house we consider concrete factory, there are beautiful plants, factories Hisense, Gree factory. Each brand factories are producing washing machines, water heaters and air conditioning.

 By comparing the two graphs above understanding, I believe we have a very abstract factory image understanding. Next we look at a specific business scenarios and be implemented in the code.

/**
 * 公共汽车
 */
public interface IBus {
    void ride();
}
/**
 * 公共工厂接口
 */
public interface CommonFactory {
    /**
     * 汽车
     * @return
     */
    ICar createCar();

    /**
     * 公共汽车
     * @return
     */
    IBus createBus();

}
public class CadillacIBus implements  IBus {
    @Override
    public void ride() {
        System.out.println("乘坐凯迪拉克公交");
    }
}
public class AudiIBus implements IBus {
    @Override
    public void ride() {
        System.out.println("乘坐奥迪公交");
    }
}
/**
 * 生产奥迪牌汽车公交车
 */
public class AudiFactory implements CommonFactory {
    @Override
    public ICar createCar() {
        return new AudiCar();
    }

    @Override
    public IBus createBus() {
        return new AudiIBus();
    }
}
/**
 * 生产凯迪拉克牌的汽车和公交车
 */
public class CadillacFactory implements CommonFactory {
    @Override
    public ICar createCar() {
        return new CadillacCar();
    }

    @Override
    public IBus createBus() {
        return new CadillacIBus();
    }
}

The client calls

/**
 * 抽象工厂测试类
 * 优点:易于扩展
 * 缺点:添加新产品,需要修改抽象工厂的接口,不符合开闭原则
 */
public class abstractFactoryTest {
    public static void main(String[] args) {
         CommonFactory commonFactory=new AudiFactory();
         commonFactory.createCar().run();
         commonFactory.createBus().ride();
    }
}

通过上面的代码,我们得知。抽象工厂非常完美清晰地描述这样一层复杂的关系。但是,不知道大家有 没有发现,如果我们再继续扩展产品等级,将其它品牌的汽车加入,那么我们的代码从抽象工厂,到具体工厂要全部调整,很显然不符合开闭原则。因此抽象工厂也是有缺点的: 1、规定了所有可能被创建的产品集合,产品族中扩展新的产品困难,需要修改抽象工厂的接口。 2、增加了系统的抽象性和理解难度。 但在实际应用中,我们千万不能犯强迫症甚至有洁癖。在实际需求中产品等级结构升级是非常正常的一件事情。我们可以根据实际情况,只要不是频繁升级,可以不遵循开闭原则。代码每半年升级一次或者每年升级一次又有何不可呢?

下面是利用工厂模式重构的实践案例

演示 JDBC 操作案例,我们每次操作是不是都需要重新创建数据库连接,每次创建其实都非常耗费性能,消耗业务调用时间。我们利用工厂模式,将数据库连接预先创建好放到容器中缓存着,在业务调用时就只需现取现用。接下来我们来看这段代码:

Pool 抽象类:

package org.jdbc.sqlhelper;
import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
/**
* 自定义连接池 getInstance()返回 POOL 唯一实例,第一次调用时将执行构造函数
* 构造函数 Pool()调用驱动装载 loadDrivers()函数;连接池创建 createPool()函数 loadDrivers()装载驱动
* createPool()建连接池 getConnection()返回一个连接实例 getConnection(long time)添加时间限制
* freeConnection(Connection con)将 con 连接实例返回到连接池 getnum()返回空闲连接数
* getnumActive()返回当前使用的连接数
*
* @author Tom
*
*/
public abstract class Pool {
public String propertiesName = "connection-INF.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 p = new Properties();
p.load(is);
this.driverName = p.getProperty("driverName");
this.maxConnect = Integer.parseInt(p.getProperty("maxConnect"));
this.normalConnect = Integer.parseInt(p.getProperty("normalConnect"));
}
/**
* 装载和注册所有 JDBC 驱动程序

* @param dri 接受驱动字符串
*/
protected void loadDrivers(String dri) {
String driverClassName = dri;
try {
driver = (Driver) Class.forName(driverClassName).newInstance();
DriverManager.registerDriver(driver);
System.out.println("成功注册 JDBC 驱动程序" + driverClassName);
} catch (Exception e) {
System.out.println("无法注册 JDBC 驱动程序:" + driverClassName + ",错误:" + e);
}
}
/**
* 创建连接池
*/
public abstract void createPool();
/**
*
* (单例模式)返回数据库连接池 Pool 的实例
*
* @param driverName 数据库驱动字符串
* @return
* @throws IOException
* @throws ClassNotFoundException
* @throws IllegalAccessException
* @throws InstantiationException
*/
public static synchronized Pool getInstance() throws IOException,
InstantiationException, IllegalAccessException,
ClassNotFoundException {
if (instance == null) {
instance.init();
instance = (Pool) Class.forName("org.e_book.sqlhelp.Pool")
.newInstance();
}
return instance;
}
/**
* 获得一个可用的连接,如果没有则创建一个连接,且小于最大连接限制
* @return

*/
public abstract Connection getConnection();
/**
* 获得一个连接,有时间限制
* @param time 设置该连接的持续时间(以毫秒为单位)
* @return
*/
public abstract Connection getConnection(long time);
/**
* 将连接对象返回给连接池
* @param con 获得连接对象
*/
public abstract void freeConnection(Connection con);
/**
* 返回当前空闲连接数
* @return
*/
public abstract int getnum();
/**
* 返回当前工作的连接数
* @return
*/
public abstract int getnumActive();
/**
* 关闭所有连接,撤销驱动注册(此方法为单例方法)
*/
protected synchronized void release() {
// /撤销驱动
try {
DriverManager.deregisterDriver(driver);
System.out.println("撤销 JDBC 驱动程序 " + driver.getClass().getName());
} catch (SQLException e) {
System.out
.println("无法撤销 JDBC 驱动程序的注册:" + driver.getClass().getName());
}
}
}

DBConnectionPool 数据库连接池:

package org.jdbc.sqlhelper;
import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.*;
import java.util.Date;
/**
* 数据库链接池管理类
* @author Tom
*
*/
public final class DBConnectionPool extends Pool {
private int checkedOut; //正在使用的连接数
/**
* 存放产生的连接对象容器
*/
private Vector<Connection> freeConnections = new Vector<Connection>(); //存放产生的连接对象容器
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()
{
if(pool == null)
{
pool = new DBConnectionPool();
}
return pool;
}

/**
* 获得一个 数据库连接池的实例
*/
private DBConnectionPool() {
try
{
init();
for (int i = 0; i < normalConnect; i++) { // 初始 normalConn 个连接
Connection c = newConnection();
if (c != null) {
freeConnections.addElement(c); //往容器中添加一个连接对象
num++; //记录总连接数
}
}
}catch(Exception e)
{
e.printStackTrace();
}
}
/**
* 初始化
* @throws IOException
*/
private void init() throws IOException
{
InputStream is = DBConnectionPool.class.getResourceAsStream(propertiesName);
Properties p = new Properties();
p.load(is);
this.userName = p.getProperty("userName");
this.passWord = p.getProperty("passWord");
this.driverName = p.getProperty("driverName");
this.url = p.getProperty("url");
this.driverName = p.getProperty("driverName");
this.maxConnect = Integer.parseInt(p.getProperty("maxConnect"));
this.normalConnect = Integer.parseInt(p.getProperty("normalConnect"));
}
/**
* 如果不再使用某个连接对象时,可调此方法将该对象释放到连接池
* @param con
*/
public synchronized void freeConnection(Connection con) {
freeConnections.addElement(con);
num++;

checkedOut- ;
numActive- ;
notifyAll(); //解锁
}
/**
* 创建一个新连接
* @return
*/
private Connection newConnection() {
Connection con = null;
try {
if (userName == null) { // 用户,密码都为空
con = DriverManager.getConnection(url);
} else {
con = DriverManager.getConnection(url, userName, passWord);
}
System.out.println("连接池创建一个新的连接");
} catch (SQLException e) {
System.out.println("无法创建这个 URL 的连接" + url);
return null;
}
return con;
}
/**
* 返回当前空闲连接数
* @return
*/
public int getnum() {
return num;
}
/**
* 返回当前连接数
* @return
*/
public int getnumActive() {
return numActive;
}
/**
* (单例模式)获取一个可用连接
* @return
*/
public synchronized Connection getConnection() {
Connection con = null;
if (freeConnections.size() > 0) { // 还有空闲的连接
num- ;
con = (Connection) freeConnections.firstElement();
freeConnections.removeElementAt(0);
try {
if (con.isClosed()) {
System.out.println("从连接池删除一个无效连接");
con = getConnection();
}
} catch (SQLException e) {
System.out.println("从连接池删除一个无效连接");
con = getConnection();
}
} else if (maxConnect == 0 || checkedOut < maxConnect) { // 没有空闲连接且当前连接小于最大允许
值,最大值为 0 则不限制
con = newConnection();
}
if (con != null) { // 当前连接数加 1
checkedOut++;
}
numActive++;
return con;
}
/**
* 获取一个连接,并加上等待时间限制,时间为毫秒
* @param timeout 接受等待时间(以毫秒为单位)
* @return
*/
public synchronized Connection getConnection(long timeout) {
long startTime = new Date().getTime();
Connection con;
while ((con = getConnection()) == null) {
try {
wait(timeout); //线程等待
} catch (InterruptedException e) {
}
if ((new Date().getTime() - startTime) >= timeout) {
return null; // 如果超时,则返回
}
}
return con;
}
/**
* 关闭所有连接
*/
public synchronized void release() {
try {
//将当前连接赋值到 枚举中
Enumeration allConnections = freeConnections.elements();
//使用循环关闭所用连接
while (allConnections.hasMoreElements()) {
//如果此枚举对象至少还有一个可提供的元素,则返回此枚举的下一个元素
Connection con = (Connection) allConnections.nextElement();
try {
con.close();
num- ;
} catch (SQLException e) {
System.out.println("无法关闭连接池中的连接");
}
}
freeConnections.removeAllElements();
numActive = 0;
} finally {
super.release();
}
}
/**
* 建立连接池
*/
public void createPool() {
pool = new DBConnectionPool();
if (pool != null) {
System.out.println("创建连接池成功");
} else {
System.out.println("创建连接池失败");
}
}
}

 

Guess you like

Origin blog.csdn.net/madongyu1259892936/article/details/93748332