防御性編程(Defensive Programming)
什么是Defensive Programming[1]?
原文:Defensive programming is a form of defensive design intended to ensure the continuing function of a piece of software under unforeseen circumstances.
_
翻譯:防御性編程是防御性設計的一種形式,它能夠保證軟件產品在不可預測的環境中持續運行。
我們可以看到,防御性編程只是防御性設計的分支,對于防御性設計,可以布滿我們生活的任何角落,尤其是設計行業和制造業,因此,理解和應用防御性編程,讓我們更好地懂得“防御”,也能將其應用于自己的生活。
防御性編程的重要思想[2]
所有的外部因素(輸入參數、環境變量、上下文)都是“邪惡”的,都存在著企圖摧毀程序的罪惡本源,為了抵制它,我們要在程序中處處檢驗,滿地設卡,不滿足條件就不再執行后續程序,以保護主程序的正確性
簡單來說就是,不管別人如何使用程序,它都能做出相應的處理,因此我們需要預測可能出現的錯誤并阻止它。
注意,不要濫用Defensive Programming,這可能讓你的程序消耗過多資源,犧牲本不必犧牲的性能(可以在文章最底部的參考資料中進一步學習)。
JDBC代碼示例
防御性編程在Java異常中的應用情況
- 當程序產生異常,對后面的影響不大(視情況,看模塊獨立性),則只需拋出異常并繼續執行
- 若程序產生異常,導致后面都不能執行,那就只能回滾重新執行,或者退出程序了
例如使用JDBC連接云端Mysql的時候,可能會斷網導致無法連接,這個時候,連登錄賬戶都不行,就需要用戶
- 要么嘗試重新連接
- 要么退出程序
給出示例代碼,注釋已經足夠清楚,不再過多解釋(代碼是基于簡單的控制臺程序)
package FinancialSystem.UsualFunction;import com.mysql.cj.jdbc.exceptions.CommunicationsException;import javax.xml.crypto.Data;
import java.net.UnknownHostException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Time;
import java.util.Scanner;/*** 執行連接數據庫操作的類** <p>* 創建日期:2020-08-04 20:44** @author 作者* @version 1.0.0* @since 1.0.0*/public class DatabaseOperating {/*** 供其他程序連接數據庫使用** <p>* 方法保證了返回值一定是非空的 Connection對象* </p>** @return Connection Object* @throws InterruptedException*/public static Connection createDatabaseLink() throws InterruptedException {Connection connection;int i = 0;for (; i < 5; i++) {connection = DatabaseOperating.createDatabase();if (connection != null) {if(i != 0){System.out.println("恭喜您,網絡連接成功!");}return connection;}System.out.println("是否嘗試重新連接?");System.out.println("1. 是 2. 否");Scanner scanner = new Scanner(System.in);System.out.print("請輸入序號:");int choose = scanner.nextInt();if(choose != 1){break;}}if (i == 5) {System.err.println("超過重連次數,請聯系相關運營商檢查您的網絡!");}for (int j = 5; j > 0; j--) {System.err.print("\r" + j + "秒后將自動退出程序");Thread.sleep(1000);}System.err.print("\r程序退出!");System.exit(0);return null;}/*** 連接本地(或云端)的Mysql數據庫** @return Connection實例*/private static Connection createDatabase() throws InterruptedException {try {String url = "jdbc:mysql://主機:端口/數據庫";String user = "用戶名";String password = "密碼";return DriverManager.getConnection(url, user, password);} catch (CommunicationsException communicationsException) {System.err.println("網絡連接錯誤!");return null;} catch (SQLException throwable) {// throwable.printStackTrace();System.err.println("遠程服務器連接失敗");for (int i = 5; i > 0; i--) {System.err.print("\r" + i + "秒后將自動退出程序");Thread.sleep(1000);}System.err.print("\r程序退出!");System.exit(0);}return null;}
}
方法的調用,能夠保證,connection一定不是null,也就能夠保證后面的一些步驟避免一些問題,例如NullPointerException
。
舉例如下(部分代碼):
String sql = "sql語句";try (Connection connection = DatabaseOperating.createDatabaseLink();PreparedStatement preparedStatement = connection.prepareStatement(sql)
) {// <代碼部分>
} catch (SQLException | InterruptedException throwable) {throwable.printStackTrace();
}
思考點
以下是我的思考,對于初學者,我想暫時我暫時沒有必要花精力于此處,目前這些也沒有搜集專業資料,僅供思考,這一小節可以忽略掉。
- JDBC不應該使用一個具備大量的MySQL賬戶,這是危險的,我們應該分配多個具備專門權限的賬戶,去處理不同的信息。
- 不應該使用明碼表示MySQL賬戶,如果那樣的話,使用逆向工程,很容易被找到和破解,這樣不太安全,例如,可以將賬戶存在隱秘的地方以密碼傳輸,在程序中解碼;又或者使用低等權限賬戶登錄數據庫,從數據庫獲取具備操作權限的賬戶信息,再用該賬戶登錄數據庫。
參考資料
[1] Wikipedia: Defensive Programming
[2] 防御性編程的核心思想