單例模式確保一個(gè)類只有一個(gè)實(shí)例,適用于資源管理、配置中心等場(chǎng)景,推薦使用靜態(tài)內(nèi)部類實(shí)現(xiàn);工廠模式解耦對(duì)象創(chuàng)建過程,適用于根據(jù)不同參數(shù)動(dòng)態(tài)創(chuàng)建子類對(duì)象的場(chǎng)景,如支付系統(tǒng);觀察者模式用于一對(duì)多依賴關(guān)系,實(shí)現(xiàn)事件驅(qū)動(dòng)機(jī)制,如訂單創(chuàng)建后觸發(fā)多個(gè)操作;模板方法模式封裝算法骨架,適用于步驟固定但部分實(shí)現(xiàn)變化的場(chǎng)景,如導(dǎo)出報(bào)表。這四種模式在實(shí)際項(xiàng)目中常組合使用,提升代碼可維護(hù)性和擴(kuò)展性。
在Java開發(fā)中,設(shè)計(jì)模式的合理使用可以提升代碼的可維護(hù)性和擴(kuò)展性。很多人學(xué)過設(shè)計(jì)模式,但實(shí)際項(xiàng)目里怎么用,什么時(shí)候用卻常常拿不準(zhǔn)。這篇文章就結(jié)合幾個(gè)常見的設(shè)計(jì)模式,講講它們?cè)谡鎸?shí)項(xiàng)目中的典型應(yīng)用場(chǎng)景和寫法。
單例模式:確保一個(gè)類只有一個(gè)實(shí)例
單例模式是用得最多的模式之一,特別是在管理資源、配置中心或者工具類中非常常見。比如數(shù)據(jù)庫連接池、日志工廠等場(chǎng)景下,我們通常希望全局只有一份實(shí)例,避免重復(fù)創(chuàng)建帶來的開銷。
實(shí)現(xiàn)方式上,最推薦使用靜態(tài)內(nèi)部類的方式:
立即學(xué)習(xí)“Java免費(fèi)學(xué)習(xí)筆記(深入)”;
public class DBConnectionPool { private DBConnectionPool() {} private static class Holder { private static final DBConnectionPool INSTANCE = new DBConnectionPool(); } public static DBConnectionPool getInstance() { return Holder.INSTANCE; } }
這種方式既保證了線程安全,又實(shí)現(xiàn)了懶加載。在spring框架中,很多Bean默認(rèn)就是單例作用域,背后也是類似的機(jī)制。
工廠模式:解耦對(duì)象的創(chuàng)建過程
工廠模式常用于需要根據(jù)參數(shù)動(dòng)態(tài)創(chuàng)建不同子類對(duì)象的場(chǎng)景。比如支付系統(tǒng)中,根據(jù)用戶選擇的不同支付方式(支付寶、微信、銀聯(lián))來創(chuàng)建對(duì)應(yīng)的支付處理器。
舉個(gè)例子,定義一個(gè)接口:
public interface PaymentHandler { void pay(double amount); }
然后有多個(gè)實(shí)現(xiàn)類,如 AlipayHandler、WechatPayHandler 等。這時(shí)候可以通過一個(gè)工廠類來統(tǒng)一創(chuàng)建:
public class PaymentFactory { public static PaymentHandler getHandler(String type) { switch (type) { case "alipay": return new AlipayHandler(); case "wechat": return new WechatPayHandler(); default: throw new IllegalArgumentException("Unsupported payment type"); } } }
這樣調(diào)用方只需要傳入類型,不需要關(guān)心具體實(shí)現(xiàn)類,也方便后續(xù)擴(kuò)展新的支付方式。
觀察者模式:實(shí)現(xiàn)事件驅(qū)動(dòng)機(jī)制
觀察者模式適用于一對(duì)多的依賴關(guān)系,當(dāng)被觀察對(duì)象狀態(tài)變化時(shí),通知所有觀察者進(jìn)行響應(yīng)。在Java中,這個(gè)模式廣泛應(yīng)用于事件監(jiān)聽機(jī)制,比如GUI界面按鈕點(diǎn)擊、消息隊(duì)列的消費(fèi)者訂閱等。
舉個(gè)簡單的業(yè)務(wù)例子:訂單下單后要發(fā)短信、發(fā)郵件、更新庫存等多個(gè)操作。
我們可以定義一個(gè)事件監(jiān)聽器接口:
public interface OrderListener { void onOrderCreated(OrderEvent event); }
然后不同的處理邏輯實(shí)現(xiàn)該接口,并注冊(cè)到訂單服務(wù)中。訂單創(chuàng)建時(shí)觸發(fā)事件廣播:
public class OrderService { private List<OrderListener> listeners = new ArrayList<>(); public void addListener(OrderListener listener) { listeners.add(listener); } public void createOrder(Order order) { // 創(chuàng)建訂單邏輯... OrderEvent event = new OrderEvent(order); for (OrderListener listener : listeners) { listener.onOrderCreated(event); } } }
這種結(jié)構(gòu)讓訂單核心邏輯與后續(xù)動(dòng)作解耦,新增功能只需添加監(jiān)聽器即可,無需修改主流程。
模板方法模式:封裝算法骨架
模板方法模式適合那些步驟固定但部分步驟實(shí)現(xiàn)可能變化的場(chǎng)景。比如導(dǎo)出報(bào)表,流程可能是:準(zhǔn)備數(shù)據(jù) → 生成文件內(nèi)容 → 寫入文件 → 發(fā)送郵件,其中“生成文件內(nèi)容”這一步會(huì)因文件格式(excel、PDF)而不同。
定義一個(gè)抽象類:
public abstract class ReportExporter { public final void export() { preparedata(); String content = generateContent(); // 子類實(shí)現(xiàn) writeFile(content); sendEmail(); } private void prepareData() { /* 公共邏輯 */ } protected abstract String generateContent(); private void writeFile(String content) { /* 寫入文件邏輯 */ } private void sendEmail() { /* 發(fā)送郵件邏輯 */ } }
然后子類只需關(guān)注內(nèi)容生成部分:
public class ExcelExporter extends ReportExporter { @Override protected String generateContent() { return "Excel格式的數(shù)據(jù)內(nèi)容"; } }
這樣整體流程統(tǒng)一控制,局部靈活擴(kuò)展,非常適合構(gòu)建標(biāo)準(zhǔn)化流程的模塊。
這些設(shè)計(jì)模式在實(shí)際項(xiàng)目中不是孤立存在的,很多時(shí)候會(huì)組合使用。比如spring框架中,IoC容器本身大量使用了工廠模式和代理模式;事件監(jiān)聽體系則是基于觀察者模式;AOP底層則涉及到了裝飾器模式和動(dòng)態(tài)代理。
掌握它們的關(guān)鍵在于理解適用場(chǎng)景和解決的問題,而不是死記硬背。只要在合適的上下文中使用,就能真正提升代碼質(zhì)量。
基本上就這些,不復(fù)雜但容易忽略的是如何在真實(shí)業(yè)務(wù)中找到合適的位置去應(yīng)用它們。