装饰者设计模式
该设计模式在之前说过,如果想要对某个对象的功能进行扩展时,就可以使用装饰者设计模式。
装饰者设计模式的使用方式:
- 编写一个类,实现与被包装类相同的接口。
- 定义一个被包装类类型的变量。
- 定义构造方法,把被包装类的对象注入,给被包装类变量赋值。
- 对于不需要改写的方法,调用原有的方法。
- 对于需要改写的方法,写自己的代码。
目前的问题在于我们不希望Connection对象中的close方法关闭连接,而是希望去将连接返回到池中,这时就需要对Connection类进行包装。因为我们使用的Mysql数据库,所以这里面实际上是对com.mysql.jdbc.Connection的包装。根据上面的方式,来包装一下Connection类。
创建MyConnection类实现Connection接口,在重写close方法时,将连接重新放回到池中:
/**
* 使用装饰者设计模式重新装饰Connection
*
*/
public class MyConnection implements Connection {//1. 编写一个类,实现与被包装类相同的接口。
//2.定义一个被包装类类型的变量。
private Connection oldConnection;//com.mysql.jdbc.Connection
private LinkedList<Connection> pool;//连接池对象
//3.定义构造方法,把被包装类的对象注入,给被包装类变量赋值。
public MyConnection(Connection oldConnection,LinkedList<Connection> pool){
this.oldConnection = oldConnection;//得到com.mysql.jdbc.Connection
this.pool = pool;//得到连接池对象
}
//5.对于需要改写的方法,写自己的代码。
@Override
public void close() throws SQLException {
//将连接重新放回到池中,而不是将其关闭
pool.addLast(oldConnection);
}
//后面代码省略
....
....
}
新创建一个数据库连接池,在获取连接时即调用getConnection方法的时候,将原有的Connection修改为我们包装好的MyConnection类:
package com.monkey1024.jdbc.pool;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.Collections;
import java.util.LinkedList;
import java.util.logging.Logger;
import javax.sql.DataSource;
import com.monkey1024.jdbc.util.DBUtil;
/**
* 数据库连接池规范
*
*/
public class MyPoolClosed implements DataSource {
// 创建一个存放连接的池子
private static LinkedList<Connection> pool = (LinkedList<Connection>) Collections
.synchronizedList(new LinkedList<Connection>());
static {
try {
for (int i = 0; i < 10; i++) {
Connection conn = DBUtil.getConnection();
pool.add(conn);
}
} catch (Exception e) {
throw new ExceptionInInitializerError("初始化数据库连接失败,请检查配置文件是否正确!");
}
}
public Connection getConnection() throws SQLException {
Connection conn = null;
if (pool.size() > 0) {
//将连接池中的一个连接取出
conn = pool.removeFirst();
//得到一个包装后的MyConnection对象,这样调用的close方法就是我们包装之后的close方法
MyConnection myConn = new MyConnection(conn,pool);
return myConn;
} else {
// 此时说明连接池中已经没有空闲连接了,需要等待
throw new RuntimeException("服务器忙。。。");
}
}
//后面代码省略
....
....
}
创建一个数据库连接池的测试类:
package com.monkey1024.jdbc.pool;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import javax.sql.DataSource;
/**
* 数据库连接池测试类
*
*/
public class PoolTest02 {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement ps = null;
DataSource ds = new MyPool();
try {
conn = ds.getConnection();//从池中取出一个连接 MyConnection
ps = conn.prepareStatement("..");
// ...
} catch (SQLException e) {
e.printStackTrace();
}finally{
try {
//该关就关闭,是否真的关闭,取决于使用的是哪个conn对象
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
使用适配器模式修改代码
上面的代码还是有一些问题,就是在包装的时候不需要将所有的方法都重写,上面代码有些乱,这里可以使用适配器模式来完善。
创建一个适配器:
/**
* 适配器模式
*
* 1、编写一个类,实现与被包装类相同的接口。
* 2、定义一个被包装类类型的变量。
* 3、定义构造方法,把被包装类的对象注入,给被包装类变量赋值。
* 4、对于不需要改写的方法,调用原有的方法。
*/
public class MyWrap implements Connection {
private Connection oldConn;
public MyWrap(Connection oldConn){
this.oldConn = oldConn;
}
@Override
public <T> T unwrap(Class<T> iface) throws SQLException {
return oldConn.unwrap(iface);
}
@Override
public boolean isWrapperFor(Class<?> iface) throws SQLException {
return oldConn.isWrapperFor(iface);
}
@Override
public Statement createStatement() throws SQLException {
return oldConn.createStatement();
}
//后面代码省略
....
....
}
创建自定义的Connection类去实现上面的MyWrap适配器,这样代码就显得简洁许多:
public class MyConnection extends MyWrap {
private Connection oldConn;
private LinkedList<Connection> pool;
public MyConnection(Connection oldConn,LinkedList<Connection> pool) {
super(oldConn);
this.oldConn = oldConn;
this.pool = pool;
}
@Override
public void close() throws SQLException {
pool.addLast(oldConn);
}
}
海报
0 条评论
187
相关文章
本站已关闭游客评论,请登录或者注册后再评论吧~