欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

代码重构篇之如何写出优雅的代码?

程序员文章站 2022-03-26 19:25:24
文章目录如何写出优雅的代码?案例分析重构后的代码持续优化总结如何写出优雅的代码?案例分析重构后的代码持续优化总结...

如何写出优雅的代码?

  1. 熟悉软件架构设计原则。尽量符合开闭原则,依赖注入等原则,让代码的结构清晰明了、易于维护。
  2. 使用恰当的设计模式,比如使用工厂模式来创建不同类型的实例,观察者模式监听和管理不同的客户端等,设计模式让我们的代码能够精简到最小化、极致。
  3. 尽可能地提高代码的可扩展性,比如使用代理、反射、泛型等技术让代码能够更*、易扩展。
  4. 熟悉使用UML类图,类图能够让程序的设计结构清晰的反映出来。
  5. 尽量提高代码的可重用性,例如抽离出重复代码、优化算法、使用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>

  1. 读取配置文件前,提前把.properties文件放到resources目录下,通过类加载机制加载
    InputStream is = DBConnectionPool.class.getClassLoader().getResourceAsStream(propertiesName);

  2. 为什么选择 使用vector来存放连接? vector与arrayList的区别是什么?
    &emsp 因为vector是线程安全的, 新增或减少连接是安全的。 arrayList是线程不安全的,访问速度快,但不能保证数据的一致性。
    区别:
    ① vector是线程安全的, 占用系统的资源多。
    ② vector每次扩容的容量为默认为原来的2倍,arrayList默认扩容的容量为1.5倍。

  3. 怎么获取一个可用的连接?

    1. 判断连接池的的数量是不是大于0,如果大于0,那么就从连接池中取出一个,同时时连接的数量-1。
    2. 如果连接池的数量满了,但是没有超过最大的连接数,那么可以再创建一个连接放入到连接池里。
  4. 关闭数据库后,如何优雅的释放连接?
    在父类里定义卸载驱动类,在子类里将缓存容器里的所有连接释放。

本文地址:https://blog.csdn.net/qq_33036061/article/details/110847592