系列文章
關于時間復雜度o(1), o(n), o(logn), o(nlogn)的理解
關于HashMap的哈希碰撞、拉鏈法和key的哈希函數設計
關于JVM內存模型和堆內存模型的理解
關于代理模式的理解
關于Mysql基本概念的理解
關于軟件設計模式的理解
文章目錄
- 前言
- 一、軟件設計模式遵循的六大原則
- 二、學習軟件設計模式的意義
- 三、使用率最高的設計模式有哪幾個?具體使用場景舉例
- 1.單例模式(Singleton)
- 2.工廠模式(Factory)
- 3.觀察者模式(Observer)
- 4.策略模式(Strategy)
前言
軟件設計模式(Software Design Pattern),是一套被反復使用的、關于代碼設計經驗的總結。被用來解決一些不斷重復發生的問題,是前輩們的代碼設計經驗的總結,具有一定的普遍性,可以反復使用。其目的是為了提高代碼的可重用性、代碼的可讀性和代碼的可靠性
一、軟件設計模式遵循的六大原則
設計模式通常遵循的六大原則是:
開放封閉原則(Open/Closed Principle,OCP): 軟件實體(類、模塊、函數等)應該對擴展開放,對修改關閉。這意味著在不修改現有代碼邏輯的情況下,能夠通過擴展來增加新的功能。
單一職責原則(Single Responsibility Principle,SRP): 一個類應該只負責一種類型的任務或職責。
里氏替換原則(Liskov Substitution Principle,LSP): 子類型必須能夠替換掉它們的父類型,而不影響程序的正確性。
依賴倒置原則(Dependency Inversion Principle,DIP): 應該依賴于接口或抽象類,而不是具體的實現。
接口隔離原則(Interface Segregation Principle,ISP): 一個類不應該依賴它不需要的接口。
合成/聚合復用原則(Composition/Aggregation Reuse Principle,CARP): 應該優先使用對象組合或聚合,而不是繼承來實現代碼復用。
這些原則提供了指導,幫助開發人員設計出靈活、可維護、可擴展和易于理解的軟件系統。雖然并不是每種設計模式都嚴格遵循這些原則,但設計模式通常是以這些原則為基礎來提供解決特定問題的通用方案
二、學習軟件設計模式的意義
設計模式的本質是面向對象設計原則的實際運用,是對類的封裝性、繼承性和多態性以及類的關聯關系和組合關系的充分理解。正確使用設計模式具有以下優勢。:
- 可以提高程序員的思維能力、編程能力和設計能力。
- 可以使程序設計更加標準化、代碼編制更加工程化,使軟件開發效率大大提高,從而縮短軟件的開發周期。
- 可以使設計的代碼可復用性高、可讀性強、可靠性高、靈活性好、可維護性強。
三、使用率最高的設計模式有哪幾個?具體使用場景舉例
1.單例模式(Singleton)
場景舉例: 當系統中需要確保一個類只有一個實例,并提供全局訪問點時,通常使用單例模式。如數據庫連接池、日志管理器等
代碼案例:
步驟 1: 創建單例類
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;public class DatabaseConnection {// 數據庫連接相關配置private static final String URL = "jdbc:mysql://localhost:3306/mydatabase";private static final String USERNAME = "username";private static final String PASSWORD = "password";// 私有靜態變量,保存類的唯一實例private static DatabaseConnection instance;// 數據庫連接對象private Connection connection;// 私有構造函數,防止外部直接創建對象private DatabaseConnection() {try {// 創建數據庫連接connection = DriverManager.getConnection(URL, USERNAME, PASSWORD);} catch (SQLException e) {e.printStackTrace();}}// 公有靜態方法,返回唯一實例public static DatabaseConnection getInstance() {if (instance == null) {// 確保線程安全synchronized (DatabaseConnection.class) {if (instance == null) {instance = new DatabaseConnection();}}}return instance;}// 獲取數據庫連接對象public Connection getConnection() {return connection;}
}
步驟 2: 使用單例類
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;public class Main {public static void main(String[] args) {// 獲取數據庫連接Connection connection = DatabaseConnection.getInstance().getConnection();// 執行數據庫操作try {PreparedStatement statement = connection.prepareStatement("SELECT * FROM users");ResultSet resultSet = statement.executeQuery();while (resultSet.next()) {System.out.println("User ID: " + resultSet.getInt("id") + ", Name: " + resultSet.getString("name"));}resultSet.close();statement.close();} catch (SQLException e) {e.printStackTrace();}}
}
解釋
單例模式的核心: 私有構造函數和一個返回實例的公有靜態方法。
線程安全: 使用雙重檢查鎖定確保在多線程環境下安全創建實例。
延遲初始化: 實例在類被加載時不會創建,在首次需要時才創建,節省資源。
數據庫連接池: 這種方式也可以用于實現簡單的數據庫連接池,通過控制并發訪問來管理連接數,提高數據庫連接的效率和資源利用率。
這種實現方式在實際應用中非常有用,特別是在需要頻繁訪問數據庫的情況下,可以減少連接的開銷和管理成本。
2.工廠模式(Factory)
場景舉例: 當需要創建多個具有相似功能的對象時,使用工廠模式可以將對象的創建邏輯封裝在一個工廠類中,提高代碼的靈活性和可維護性。如數據庫驅動管理等
代碼案例:
步驟 1: 創建接口
import java.sql.Connection;public interface DatabaseConnection {Connection getConnection();
}
步驟 2: 創建具體實現類
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;public class MySQLConnection implements DatabaseConnection {// MySQL數據庫連接相關配置private static final String URL = "jdbc:mysql://localhost:3306/mydatabase";private static final String USERNAME = "username";private static final String PASSWORD = "password";@Overridepublic Connection getConnection() {Connection connection = null;try {// 創建MySQL數據庫連接connection = DriverManager.getConnection(URL, USERNAME, PASSWORD);} catch (SQLException e) {e.printStackTrace();}return connection;}
}
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;public class PostgreSQLConnection implements DatabaseConnection {// PostgreSQL數據庫連接相關配置private static final String URL = "jdbc:postgresql://localhost:5432/mydatabase";private static final String USERNAME = "username";private static final String PASSWORD = "password";@Overridepublic Connection getConnection() {Connection connection = null;try {// 創建PostgreSQL數據庫連接connection = DriverManager.getConnection(URL, USERNAME, PASSWORD);} catch (SQLException e) {e.printStackTrace();}return connection;}
}
步驟 3: 創建工廠類
public class ConnectionFactory {public static DatabaseConnection getDatabaseConnection(String dbType) {if (dbType.equalsIgnoreCase("MySQL")) {return new MySQLConnection();} else if (dbType.equalsIgnoreCase("PostgreSQL")) {return new PostgreSQLConnection();}return null;}
}
步驟 4: 使用工廠模式獲取數據庫連接
import java.sql.Connection;public class Main {public static void main(String[] args) {// 獲取MySQL數據庫連接DatabaseConnection mysqlConnection = ConnectionFactory.getDatabaseConnection("MySQL");Connection mysqlConn = mysqlConnection.getConnection();// 獲取PostgreSQL數據庫連接DatabaseConnection postgresConnection = ConnectionFactory.getDatabaseConnection("PostgreSQL");Connection postgresConn = postgresConnection.getConnection();// 使用數據庫連接執行操作...}
}
解釋
工廠模式的核心: 根據條件動態創建對象,將創建邏輯封裝在工廠類中,客戶端無需關心具體的創建細節。
可擴展性: 當需要新增其他類型的數據庫連接時,只需在工廠類中添加相應的創建邏輯即可,不需要修改客戶端代碼。
解耦: 客戶端與具體數據庫連接類之間解耦,通過工廠類進行統一管理,降低了代碼的耦合度。
工廠模式能夠很好地應對數據庫驅動管理場景中的需求變化,使得代碼更加靈活和可維護。
3.觀察者模式(Observer)
場景舉例: 當一個對象的狀態發生改變時,需要通知其他相關對象,并自動更新它們的狀態時,通常使用觀察者模式。如消息訂閱與發布系統等
代碼案例:
步驟 1: 創建主題接口
首先,定義一個主題接口,用于注冊、刪除和通知觀察者。
public interface Subject {void registerObserver(Observer observer);void removeObserver(Observer observer);void notifyObservers();
}
步驟 2: 創建觀察者接口
然后,定義一個觀察者接口,用于接收主題的通知。
public interface Observer {void update(String message);
}
步驟 3: 創建具體主題類
接下來,創建具體的主題類,實現主題接口,并維護觀察者列表,以及在狀態變化時通知觀察者。
import java.util.ArrayList;
import java.util.List;public class MessageTopic implements Subject {private List<Observer> observers;private String message;public MessageTopic() {this.observers = new ArrayList<>();}@Overridepublic void registerObserver(Observer observer) {observers.add(observer);}@Overridepublic void removeObserver(Observer observer) {observers.remove(observer);}@Overridepublic void notifyObservers() {for (Observer observer : observers) {observer.update(message);}}public void setMessage(String message) {this.message = message;notifyObservers();}
}
步驟 4: 創建具體觀察者類
然后,創建具體的觀察者類,實現觀察者接口,并在接收到通知時執行相應的操作。
public class MessageSubscriber implements Observer {private String name;public MessageSubscriber(String name) {this.name = name;}@Overridepublic void update(String message) {System.out.println(name + " received message: " + message);}
}
步驟 5: 使用觀察者模式
最后,在應用程序中使用觀察者模式。
public class Main {public static void main(String[] args) {// 創建主題MessageTopic topic = new MessageTopic();// 創建觀察者Observer subscriber1 = new MessageSubscriber("Subscriber 1");Observer subscriber2 = new MessageSubscriber("Subscriber 2");// 注冊觀察者topic.registerObserver(subscriber1);topic.registerObserver(subscriber2);// 發布消息topic.setMessage("Hello, world!");}
}
解釋
主題接口: 定義了注冊、刪除和通知觀察者的方法。
觀察者接口: 定義了觀察者需要實現的更新方法。
具體主題類: 實現了主題接口,維護了觀察者列表,并在狀態變化時通知所有觀察者。
具體觀察者類: 實現了觀察者接口,定義了接收通知時的具體行為。
使用觀察者模式: 創建主題對象,創建觀察者對象并注冊到主題中,然后發布消息。所有注冊的觀察者都會接收到消息通知并執行相應的操作。
觀察者模式非常適用于消息訂閱與發布場景,可以實現松耦合的通信機制,讓發布者和訂閱者之間的關系更加靈活。
4.策略模式(Strategy)
場景舉例: 當需要在運行時根據不同的情況選擇算法或行為時,使用策略模式可以將不同的算法封裝成不同的策略類,使得算法的變化獨立于使用算法的客戶。如支付系統中的支付策略等
代碼案例:
步驟 1: 創建支付策略接口
首先,定義一個支付策略接口,用于定義支付的方法。
public interface PaymentStrategy {void pay(double amount);
}
步驟 2: 創建具體的支付策略類
然后,創建具體的支付策略類,實現支付策略接口,每個具體的支付策略類代表一種支付方式,例如信用卡支付、支付寶支付、微信支付等
public class CreditCardPayment implements PaymentStrategy {private String cardNumber;private String expiryDate;private String cvv;public CreditCardPayment(String cardNumber, String expiryDate, String cvv) {this.cardNumber = cardNumber;this.expiryDate = expiryDate;this.cvv = cvv;}@Overridepublic void pay(double amount) {System.out.println("Paid " + amount + " via credit card.");}
}public class AlipayPayment implements PaymentStrategy {private String account;public AlipayPayment(String account) {this.account = account;}@Overridepublic void pay(double amount) {System.out.println("Paid " + amount + " via Alipay.");}
}public class WechatPayment implements PaymentStrategy {private String account;public WechatPayment(String account) {this.account = account;}@Overridepublic void pay(double amount) {System.out.println("Paid " + amount + " via WeChat.");}
}
步驟 3: 創建上下文類
接下來,創建上下文類,用于持有具體的支付策略對象,并提供支付方法。
public class PaymentContext {private PaymentStrategy paymentStrategy;public PaymentContext(PaymentStrategy paymentStrategy) {this.paymentStrategy = paymentStrategy;}public void setPaymentStrategy(PaymentStrategy paymentStrategy) {this.paymentStrategy = paymentStrategy;}public void pay(double amount) {paymentStrategy.pay(amount);}
}
步驟 4: 使用策略模式
最后,在應用程序中使用策略模式進行支付。
public class Main {public static void main(String[] args) {// 創建支付上下文PaymentContext paymentContext = new PaymentContext(new CreditCardPayment("1234 5678 9012 3456", "12/24", "123"));// 進行支付paymentContext.pay(100.0);// 切換支付方式paymentContext.setPaymentStrategy(new AlipayPayment("example@example.com"));// 進行支付paymentContext.pay(200.0);}
}
解釋
支付策略接口: 定義了支付的方法。
具體的支付策略類: 實現了支付策略接口,每個類代表一種支付方式,實現了具體的支付邏輯。
支付上下文類: 持有具體的支付策略對象,并提供支付方法,客戶端通過上下文類進行支付。
使用策略模式: 創建支付上下文對象,根據需要設置不同的支付策略,然后進行支付操作。
策略模式能夠有效地解耦客戶端和具體的支付策略,使得支付系統更加靈活,易于擴展和維護。