代码重构篇之如何写出优雅的代码?
程序员文章站
2022-03-26 19:25:24
文章目录如何写出优雅的代码?案例分析重构后的代码持续优化总结如何写出优雅的代码?案例分析重构后的代码持续优化总结...
如何写出优雅的代码?
- 熟悉软件架构设计原则。尽量符合开闭原则,依赖注入等原则,让代码的结构清晰明了、易于维护。
- 使用恰当的设计模式,比如使用工厂模式来创建不同类型的实例,观察者模式监听和管理不同的客户端等,设计模式让我们的代码能够精简到最小化、极致。
- 尽可能地提高代码的可扩展性,比如使用代理、反射、泛型等技术让代码能够更*、易扩展。
- 熟悉使用UML类图,类图能够让程序的设计结构清晰的反映出来。
- 尽量提高代码的可重用性,例如抽离出重复代码、优化算法、使用SpringAop切面编程手段统计日志等。
案例分析(一)
当我们使用JDBC去连接数据库时,我们每次操作都要去重新创建数据库连接,每次创建其实都是非常耗时的,使用工厂模式重构JDBC操作数据库连接, 让工厂去创建和维护数据库连接实例,然后放到容器中缓存,在业务调用的时候取出来用即可。
重构后的代码
Pool抽象类
Pool 类相当于一个抽象工厂,定义了生产连接、释放连接、创建连接池等抽象方法,由子类DBConnectionPool去实现和创建这些方法,这些方法在DBConnectionPool被创建的时候就创建好了,用连接池的时候我们只需要调用业务方法即可。
package patternsDesign.factoryPractice;
import patternsDesign.factoryPractice.utils.JDBCUtils;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.Driver;
import java.sql.DriverManager;
import java.util.Properties;
// Pool抽象类
public abstract class Pool {
public String propertiesName = "db.properties";
//1. 定义唯一实例
private static Pool instance;
//2. 最大连接数
protected Integer maxConnection;
//3. 保持连接数
protected Integer stayConnection;
//4. 驱动
protected String driverName;
protected Driver driver;
protected Pool() {
//
init();
// 加载驱动
LoadDriver(driverName);
}
private void init() {
Properties properties = new Properties();
InputStream is = JDBCUtils.class.getClassLoader().getResourceAsStream(propertiesName);
try {
properties.load(is);
} catch (IOException e) {
e.printStackTrace();
}
String diver = properties.getProperty("driver");
String url = properties.getProperty("url");
String username = properties.getProperty("username");
String password = properties.getProperty("password");
Integer maxConnect = Integer.parseInt(properties.getProperty("maxConnection"));
Integer stayConnection = Integer.parseInt(properties.getProperty("stayConnection"));
this.driverName = diver;
this.maxConnection = maxConnect;
this.stayConnection = stayConnection;
}
private void LoadDriver(String driverName) {
String driverClassName = driverName;
try {
driver = (Driver) Class.forName(driverClassName).newInstance();
DriverManager.registerDriver(driver);
System.out.println("注册驱动成功!" + driverClassName);
} catch (Exception e) {
System.out.println("无法注册JDBC驱动!" + driverClassName + "异常:" + e);
}
}
//使用简单工厂模式创建连接池
public static Pool createPool(Class<? extends Pool> clazz) {
try {
if (null != clazz) {
return clazz.newInstance();
}
} catch (Exception e) {
}
return null;
}
/***
*
* 单例模式返回连接池实例
*/
public static synchronized Pool getInstance() throws ClassNotFoundException, IllegalAccessException, InstantiationException {
if (instance == null) {
instance.init();
instance = (Pool) Class.forName("org.e_book.sqlhelp.Pool").newInstance();
}
return instance;
}
// 从连接池返回一个连接,如果没有则创建一个连接,且小于最大连接
public abstract Connection getConnection();
// 获得一个连接,限制等待时间
public abstract Connection getConnection(long time);
// 将连接对象返回给连接池
public abstract void freeConnection(Connection connection);
// 返回当前空闲连接数
public abstract Integer getNum();
// 返回当前工作连接数
public abstract Integer getActiveNum();
// 卸载驱动
protected synchronized void release() {
try {
DriverManager.deregisterDriver(driver);
System.out.println("撤销驱动成功!");
} catch (Exception e) {
System.out.println("撤销驱动失败!" + driverName + "异常:" + e);
}
}
}
DBConnectionPool 继承Pool类
package patternsDesign.factoryPractice;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.util.*;
// 定义连接池,用final修饰对外不可继承和修改
public final class DBConnectionPool extends Pool {
//正在使用的连接数
private int usingNum;
// 存放产生连接的对象容器
private Vector<Connection> freeConnections = new Vector<>();
private String url = null;
private String userName = null;
private String passWord = null;
// 在活跃的连接数,默认为0,指的是在连接池外面的数量之和
private static int activeNum = 0;
// 空闲的连接数, 放入到连接池里的连接数量
private static int num = 0;
//连接池实例
private static DBConnectionPool dbConnectionPool = null;
// 使用单例模式获取连接池
public static DBConnectionPool getInstance() {
if (dbConnectionPool == null) {
return new DBConnectionPool();
}
return dbConnectionPool;
}
//初始化
public void init() throws IOException {
//加载配置文件
InputStream is = DBConnectionPool.class.getClassLoader().getResourceAsStream(propertiesName);
Properties properties = new Properties();
properties.load(is);
String diver = properties.getProperty("driver");
String url = properties.getProperty("url");
String username = properties.getProperty("username");
String password = properties.getProperty("password");
Integer maxConnect = Integer.parseInt(properties.getProperty("maxConnection"));
Integer stayConnection = Integer.parseInt(properties.getProperty("stayConnection"));
this.driverName = diver;
this.maxConnection = maxConnect;
this.stayConnection = stayConnection;
this.url = url;
this.userName = username;
this.passWord = password;
}
// @Override
// public void createPool() {
// dbConnectionPool = new DBConnectionPool();
// if (dbConnectionPool != null) {
// System.out.println("创建连接池成功!");
// } else {
// System.out.println("创建连接池失败!");
// }
// }
//创建一个新连接
private Connection newConnection() {
Connection connection = null;
try {
if (userName == null) {
connection = DriverManager.getConnection(url);
} else {
connection = DriverManager.getConnection(url, userName, passWord);
}
} catch (Exception e) {
System.out.println("创建连接失败!" + e);
}
return connection;
}
//使用单例模式,获取一个可用连接
@Override
public synchronized Connection getConnection() {
Connection connection = null;
if (freeConnections.size() > 0) {
try {
num--; //空闲连接数
connection = freeConnections.firstElement();
freeConnections.removeElementAt(0);
if (connection.isClosed()) {
System.out.println("从连接池中删除一个无效连接!");
connection = getConnection();
}
} catch (Exception e) {
System.out.println("从连接池中删除一个无效连接");
connection = getConnection();
}
} else if (maxConnection == 0 || usingNum < maxConnection) {
//最大值为0,则不受限制
connection = newConnection();
}
if (connection != null) {
//正在使用的连接数
usingNum++;
}
//可用的连接数量+1
activeNum++;
return connection;
}
@Override
public synchronized Connection getConnection(long time) {
//在time内获取一个连接
long startTime = new Date().getTime();
Connection connection = null;
while ((connection = getConnection()) == null) {
try {
wait(time);
} catch (InterruptedException e) {
e.printStackTrace();
}
//如果超时,那么返回为null
if ((new Date().getTime() - startTime) > time) {
return null;
}
}
return connection;
}
@Override
public void freeConnection(Connection connection) {
// 释放一个连接,那么可用连接也少一个,从连接池里拿出来几个就算几个可用
freeConnections.addElement(connection);
usingNum--;
activeNum--;
num++;
notifyAll();
}
@Override
public Integer getNum() {
return num;
}
@Override
public Integer getActiveNum() {
return activeNum;
}
//释放所有连接
public synchronized void release() {
try {
Enumeration allConnections = freeConnections.elements();
while (allConnections.hasMoreElements()) {
Connection conn = (Connection) allConnections.nextElement();
try {
conn.close();
num--;
} catch (Exception e) {
System.out.println("无法关闭连接池中的连接");
}
}
freeConnections.removeAllElements();
activeNum = 0;
} catch (Exception e) {
System.out.println("释放失败!");
} finally {
//卸载驱动
super.release();
}
}
}
配置文件
url=jdbc:mysql://localhost:3306/db3?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai
driver=com.mysql.jdbc.Driver
username=
password=
maxConnection=50
stayConnection=10
依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example.soft</groupId>
<artifactId>software_architecture_study</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>commons-pool</groupId>
<artifactId>commons-pool</artifactId>
<version>1.5.4</version>
</dependency>
<!--mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
</dependency>
</dependencies>
</project>
问题总结
1.数据源的依赖解决 dbcp数据源连接,连接池,mysql驱动等
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>commons-pool</groupId>
<artifactId>commons-pool</artifactId>
<version>1.5.4</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
</dependency>
-
读取配置文件前,提前把.properties文件放到resources目录下,通过类加载机制加载
InputStream is = DBConnectionPool.class.getClassLoader().getResourceAsStream(propertiesName); -
为什么选择 使用vector来存放连接? vector与arrayList的区别是什么?
&emsp 因为vector是线程安全的, 新增或减少连接是安全的。 arrayList是线程不安全的,访问速度快,但不能保证数据的一致性。
区别:
① vector是线程安全的, 占用系统的资源多。
② vector每次扩容的容量为默认为原来的2倍,arrayList默认扩容的容量为1.5倍。 -
怎么获取一个可用的连接?
- 判断连接池的的数量是不是大于0,如果大于0,那么就从连接池中取出一个,同时时连接的数量-1。
- 如果连接池的数量满了,但是没有超过最大的连接数,那么可以再创建一个连接放入到连接池里。
-
关闭数据库后,如何优雅的释放连接?
在父类里定义卸载驱动类,在子类里将缓存容器里的所有连接释放。
本文地址:https://blog.csdn.net/qq_33036061/article/details/110847592