Java開發(fā)中的常用設計模式實戰(zhàn)應用小結
在Java開發(fā)中,設計模式是解決常見軟件設計問題的可復用解決方案。它們不是代碼模板,而是經驗總結,能顯著提升代碼的可維護性、可擴展性和可重用性。根據《設計模式:可復用面向對象軟件的基礎》一書,設計模式分為創(chuàng)建型、結構型和行為型三大類。本文將深入剖析5個最常用的設計模式,結合真實業(yè)務場景,提供完整可運行的Java代碼示例。拒絕“紙上談兵”,只講實戰(zhàn)!
一、為什么需要設計模式?—— 從痛點出發(fā)
想象一個場景:
一個電商系統(tǒng)需要支持多種支付方式(微信、支付寶、信用卡),但支付邏輯分散在多個Service中。當新增支付方式時,必須修改大量代碼,導致維護成本飆升,甚至引發(fā)新Bug。
這就是缺乏設計模式的典型問題:代碼緊耦合、擴展性差。設計模式的核心價值在于:將變化封裝起來,讓系統(tǒng)對擴展開放,對修改關閉。
二、實戰(zhàn)解析:5個高頻設計模式
1. 單例模式(Singleton)—— 確保全局唯一實例
核心思想:保證一個類只有一個實例,并提供全局訪問點。
適用場景:數(shù)據庫連接池、日志管理器、配置中心(避免重復初始化資源)。
為什么重要:避免資源浪費(如頻繁創(chuàng)建數(shù)據庫連接),保證狀態(tài)一致性。
實戰(zhàn)代碼:數(shù)據庫連接池
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
/**
* 單例模式:線程安全的數(shù)據庫連接池
* 使用雙重檢查鎖定(DCL)避免多線程問題
*/
public class DatabaseConnectionPool {
// volatile確保可見性,防止指令重排
private static volatile DatabaseConnectionPool instance;
private Connection connection;
private DatabaseConnectionPool() throws SQLException {
// 初始化數(shù)據庫連接(實際生產中會使用連接池框架如HikariCP)
this.connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "user", "password");
}
public static DatabaseConnectionPool getInstance() throws SQLException {
if (instance == null) {
synchronized (DatabaseConnectionPool.class) {
if (instance == null) {
instance = new DatabaseConnectionPool();
}
}
}
return instance;
}
public Connection getConnection() {
return connection;
}
// 業(yè)務使用示例
public static void main(String[] args) {
try {
DatabaseConnectionPool pool = DatabaseConnectionPool.getInstance();
Connection conn = pool.getConnection();
System.out.println("Database connection established: " + conn);
} catch (SQLException e) {
e.printStackTrace();
}
}
}關鍵點:
volatile+ 雙重檢查鎖定:解決多線程下的實例初始化問題。- 避免:直接使用
public static DatabaseConnectionPool instance = new DatabaseConnectionPool();(無法控制初始化時機)。
2. 工廠方法模式(Factory Method)—— 解耦對象創(chuàng)建
核心思想:定義創(chuàng)建對象的接口,但讓子類決定實例化哪個類。
適用場景:框架設計(如JDBC驅動、Spring Bean管理)、需要靈活擴展的場景。
為什么重要:客戶端代碼不依賴具體類,只需依賴抽象接口。
實戰(zhàn)代碼:支付方式工廠
/**
* 工廠方法模式:支付方式工廠
* 業(yè)務場景:電商系統(tǒng)支持微信、支付寶、信用卡支付
*/
// 抽象產品:支付接口
interface Payment {
void pay(int amount);
}
// 具體產品:微信支付
class WeChatPay implements Payment {
@Override
public void pay(int amount) {
System.out.println("WeChat Pay: " + amount + "元");
}
}
// 具體產品:支付寶
class Alipay implements Payment {
@Override
public void pay(int amount) {
System.out.println("Alipay: " + amount + "元");
}
}
// 工廠:根據類型創(chuàng)建支付對象
class PaymentFactory {
public Payment createPayment(String type) {
switch (type.toLowerCase()) {
case "wechat":
return new WeChatPay();
case "alipay":
return new Alipay();
default:
throw new IllegalArgumentException("Unsupported payment type: " + type);
}
}
}
// 業(yè)務調用(無需修改代碼即可新增支付方式)
public class PaymentService {
private PaymentFactory factory = new PaymentFactory();
public void processPayment(String paymentType, int amount) {
Payment payment = factory.createPayment(paymentType);
payment.pay(amount);
}
public static void main(String[] args) {
PaymentService service = new PaymentService();
service.processPayment("wechat", 100); // 輸出:WeChat Pay: 100元
service.processPayment("alipay", 200); // 輸出:Alipay: 200元
}
}關鍵點:
- 擴展性:新增支付方式只需實現(xiàn)
Payment接口 + 修改工廠,無需修改PaymentService。 - 對比:若用
if-else硬編碼,新增支付方式需修改PaymentService,違反開閉原則。
3. 觀察者模式(Observer)—— 實現(xiàn)事件驅動
核心思想:定義對象間一對多的依賴關系,當一個對象狀態(tài)改變時,所有依賴它的對象都收到通知并自動更新。
適用場景:GUI事件處理、消息訂閱(如訂單狀態(tài)變更通知、實時股價推送)。
為什么重要:解耦發(fā)布者與訂閱者,避免循環(huán)依賴。
實戰(zhàn)代碼:訂單狀態(tài)通知系統(tǒng)
import java.util.ArrayList;
import java.util.List;
/**
* 觀察者模式:訂單狀態(tài)通知
* 業(yè)務場景:用戶下單后,短信、郵件、APP推送同時通知
*/
// 主題(被觀察者)
interface OrderSubject {
void registerObserver(Observer observer);
void removeObserver(Observer observer);
void notifyObservers();
}
// 觀察者接口
interface Observer {
void update(String orderStatus);
}
// 訂單實體(被觀察者)
class Order implements OrderSubject {
private List<Observer> observers = new ArrayList<>();
private String status;
public void setStatus(String status) {
this.status = status;
notifyObservers(); // 狀態(tài)變更時通知所有觀察者
}
@Override
public void registerObserver(Observer observer) {
observers.add(observer);
}
@Override
public void removeObserver(Observer observer) {
observers.remove(observer);
}
@Override
public void notifyObservers() {
for (Observer observer : observers) {
observer.update(status);
}
}
}
// 具體觀察者:短信通知
class SmsObserver implements Observer {
@Override
public void update(String status) {
System.out.println("SMS: 訂單狀態(tài)更新為 " + status);
}
}
// 具體觀察者:郵件通知
class EmailObserver implements Observer {
@Override
public void update(String status) {
System.out.println("Email: 訂單狀態(tài)更新為 " + status);
}
}
// 業(yè)務使用
public class OrderNotificationSystem {
public static void main(String[] args) {
Order order = new Order();
// 注冊觀察者
order.registerObserver(new SmsObserver());
order.registerObserver(new EmailObserver());
// 更新訂單狀態(tài)(自動觸發(fā)通知)
order.setStatus("Shipped"); // 輸出:SMS: 訂單狀態(tài)更新為 Shipped
// Email: 訂單狀態(tài)更新為 Shipped
}
}關鍵點:
- 解耦:
Order不知道具體觀察者實現(xiàn),只需維護Observer列表。 - 擴展性:新增通知方式(如APP推送)只需實現(xiàn)
Observer,無需修改Order。
4. 策略模式(Strategy)—— 封裝算法族
核心思想:定義一系列算法,將每個算法封裝起來,使它們可以互相替換。
適用場景:排序算法、支付方式、促銷策略(如滿減、折扣)。
為什么重要:避免if-else分支爆炸,提高算法復用性。
實戰(zhàn)代碼:促銷策略引擎
/**
* 策略模式:促銷策略
* 業(yè)務場景:電商大促,支持滿減、折扣、無優(yōu)惠三種策略
*/
// 策略接口
interface PromotionStrategy {
double calculateDiscount(double originalPrice);
}
// 具體策略:滿減(滿100減20)
class FullReduction implements PromotionStrategy {
@Override
public double calculateDiscount(double originalPrice) {
return originalPrice > 100 ? originalPrice - 20 : originalPrice;
}
}
// 具體策略:折扣(85折)
class Discount implements PromotionStrategy {
@Override
public double calculateDiscount(double originalPrice) {
return originalPrice * 0.85;
}
}
// 上下文:促銷引擎
class PromotionEngine {
private PromotionStrategy strategy;
public void setStrategy(PromotionStrategy strategy) {
this.strategy = strategy;
}
public double applyPromotion(double price) {
return strategy.calculateDiscount(price);
}
}
// 業(yè)務使用
public class PromotionDemo {
public static void main(String[] args) {
PromotionEngine engine = new PromotionEngine();
// 設置滿減策略
engine.setStrategy(new FullReduction());
System.out.println("FullReduction: " + engine.applyPromotion(120)); // 輸出: 100.0
// 切換為折扣策略
engine.setStrategy(new Discount());
System.out.println("Discount: " + engine.applyPromotion(120)); // 輸出: 102.0
}
}關鍵點:
- 動態(tài)切換:運行時通過
setStrategy切換策略,無需重啟服務。 - 避免分支:相比
if (type == "full"),代碼更簡潔、可測試。
5. 適配器模式(Adapter)—— 消除接口不兼容
核心思想:將一個類的接口轉換成客戶期望的另一個接口。
適用場景:集成第三方API(如支付SDK)、遺留系統(tǒng)改造。
為什么重要:復用已有代碼,無需修改原始類。
實戰(zhàn)代碼:支付SDK適配器
/**
* 適配器模式:支付SDK適配
* 業(yè)務場景:接入新支付公司(如PayPal)的SDK,但原有系統(tǒng)使用老接口
*/
// 目標接口(系統(tǒng)期望的)
interface OldPaymentGateway {
void processPayment(double amount);
}
// 適配器:將PayPalSDK適配到OldPaymentGateway
class PayPalAdapter implements OldPaymentGateway {
private PayPalSDK payPalSDK;
public PayPalAdapter(PayPalSDK payPalSDK) {
this.payPalSDK = payPalSDK;
}
@Override
public void processPayment(double amount) {
// PayPalSDK的接口與OldPaymentGateway不一致
payPalSDK.makePayment(amount);
}
}
// 第三方SDK(無法修改)
class PayPalSDK {
public void makePayment(double amount) {
System.out.println("PayPal SDK: Processing payment of " + amount);
}
}
// 業(yè)務使用(無需修改原有代碼)
public class PaymentAdapterDemo {
public static void main(String[] args) {
OldPaymentGateway gateway = new PayPalAdapter(new PayPalSDK());
gateway.processPayment(50.0); // 輸出:PayPal SDK: Processing payment of 50.0
}
}關鍵點:
- 解耦:系統(tǒng)調用
OldPaymentGateway,適配器處理SDK差異。 - 擴展性:接入新支付公司只需新增適配器(如
AlipayAdapter),不修改核心邏輯。
三、設計模式的正確使用原則
- 不要為了用而用:如果場景簡單(如只創(chuàng)建1個對象),直接new即可,避免過度設計。
- 優(yōu)先使用標準模式:如Spring框架已內置工廠、單例等模式,優(yōu)先復用而非自己實現(xiàn)。
- 結合業(yè)務場景:策略模式適合算法變化,觀察者適合事件驅動,勿混淆。
- 代碼可讀性 > 模式數(shù)量:清晰的代碼比堆砌模式更重要。
經典名言:
“設計模式是經驗的結晶,不是代碼的枷鎖。” —— 《設計模式》作者 Erich Gamma
四、總結:設計模式是“工具”,不是“目的”
| 模式 | 適用場景 | 代碼復雜度 | 業(yè)務價值 |
|---|---|---|---|
| 單例 | 資源唯一實例(DB連接) | 低 | 資源復用、狀態(tài)一致 |
| 工廠方法 | 對象創(chuàng)建邏輯復雜(支付) | 中 | 降低耦合、擴展靈活 |
| 觀察者 | 事件通知(訂單狀態(tài)) | 中 | 解耦發(fā)布者與訂閱者 |
| 策略 | 算法動態(tài)切換(促銷) | 中 | 避免分支爆炸、提升復用 |
| 適配器 | 接口不兼容(第三方集成) | 低 | 快速集成、減少修改 |
在實際項目中,90%的場景用這5種模式即可覆蓋。記?。涸O計模式不是銀彈,而是讓代碼更“像人”——清晰、可理解、易維護。
最后建議:
- 從項目中已有的問題出發(fā),選擇最匹配的模式。
- 閱讀Spring、Guava等開源框架的源碼,學習模式的實戰(zhàn)應用。
- 用單元測試驗證模式效果(如策略模式切換策略時的正確性)。
參考資料
- 《設計模式:可復用面向對象軟件的基礎》(GoF)
- Spring Framework源碼(工廠、單例實現(xiàn))
- Java 8+特性(Lambda、Stream)與設計模式的結合(如策略模式 + 函數(shù)式接口)
本文所有代碼已通過JDK 11+編譯測試,可直接運行。設計模式不是終點,而是構建健壯系統(tǒng)的起點。在Java開發(fā)中,用好設計模式,讓代碼“說話”而非“打架”!
到此這篇關于Java開發(fā)中的常用設計模式實戰(zhàn)應用小結的文章就介紹到這了,更多相關java常用設計模式內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
SpringCloud?客戶端Ribbon負載均衡的實現(xiàn)方法
Ribbon 是 Netflix 提供的一個基于 Http 和 TCP 的客戶端負載均衡工具,且已集成在 Eureka 依賴中,這篇文章主要介紹了SpringCloud?客戶端Ribbon負載均衡的實現(xiàn)方法,需要的朋友可以參考下2022-06-06
spring boot集成mongodb的增刪改查的示例代碼
這篇文章主要介紹了spring boot集成mongodb的增刪改查的示例代碼,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2021-03-03
Java多線程環(huán)境下SimpleDateFormat類安全轉換
這篇文章主要介紹了Java多線程環(huán)境下SimpleDateFormat類安全轉換,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-02-02
Java數(shù)組創(chuàng)建的3種方法6種寫法代碼示例
這篇文章主要給大家介紹了關于Java數(shù)組創(chuàng)建的3種方法6種寫法,在Java中我們可以使用關鍵字new來創(chuàng)建一個數(shù)組,文中通過代碼介紹的非常詳細,需要的朋友可以參考下2024-01-01

