Java 23 種設計模式從踩坑到精通 | 番外外觀模式 —— 物流訂單處理實戰摘要外觀模式為子系統中的一組接口提供一個統一的高層接口讓客戶端只需一鍵操作即可完成原本需要多次調用的復雜流程。本文結合**智能物流中“訂單處理系統”**的場景完整展示如何用外觀模式封裝訂單校驗、庫存扣減、支付處理、配送調度、消息通知等五個子系統的協作讓你徹底掌握“化繁為簡”的設計精髓。?本文閱讀地圖3 分鐘速覽為什么下單流程不能直接暴露給客戶端? 外觀模式核心角色外觀類與子系統手寫物流訂單門面一行代碼完成下單、取消 外觀 vs 適配器簡化 vs 轉換 面試必問“外觀模式和適配器模式有什么區別”《Java 23 種設計模式從踩坑到精通》開篇系列介紹與目錄 正篇外觀模式 Facade —— 給復雜系統裝一個“一鍵啟動” 當前番外 · 外觀模式 × 物流訂單處理 返回系列總目錄1. 物流訂單處理的復雜流程在智能物流系統中一個簡單的下單操作背后涉及訂單校驗、庫存檢查、支付處理、運費計算、攬收調度、短信通知等多個子系統。如果讓客戶端直接調用這些子系統代碼會變得臃腫且耦合嚴重// 客戶端直接調用子系統步驟多、易遺漏、難維護OrderServiceorderServicenewOrderService();PaymentServicepaymentServicenewPaymentService();InventoryServiceinventoryServicenewInventoryService();ShippingServiceshippingServicenewShippingService();NotificationServicenotificationServicenewNotificationService();if(orderService.validateOrder(info)){if(inventoryService.checkStock(sku,quantity)){OrderorderorderService.createOrder(info);doublefeeshippingService.calculateShippingFee(address,weight);PaymentResultpaypaymentService.processPayment(order,fee);if(pay.isSuccess()){inventoryService.deductStock(sku,quantity);shippingService.schedulePickup(order);notificationService.sendShipmentNotice(order,user);}}}外觀模式的解決思路提供一個統一的LogisticsOrderFacade外觀類把上述復雜流程封裝在placeOrder()方法中。客戶端只需調用一次外觀方法無需關心內部有多少子系統、調用順序如何、出錯如何處理。1.1 你的場景該不該用外觀判斷標準是 → 用外觀否 → 用其他方式需要為多個子系統提供統一入口??子系統復雜調用步驟多??希望降低客戶端與子系統的耦合??子系統簡單只有一兩個類?直接調用即可2. 外觀模式 UML物流訂單處理場景3. 完整源碼實現3.1 子系統A訂單服務 (OrderService)importjava.util.UUID;publicclassOrderService{publicbooleanvalidateOrder(OrderInfoinfo){System.out.println( 訂單服務校驗訂單信息...);if(info.getSku()null||info.getSku().isEmpty()||info.getQuantity()0||info.getAddress()null){System.out.println( ? 訂單服務校驗失敗);returnfalse;}System.out.println( ? 訂單服務校驗通過);returntrue;}publicOrdercreateOrder(OrderInfoinfo){OrderordernewOrder(UUID.randomUUID().toString(),info);order.setStatus(OrderStatus.CREATED);System.out.printf( ? 訂單服務訂單創建成功 | 訂單號%s\n,order.getOrderId());returnorder;}publicvoidupdateOrderStatus(StringorderId,OrderStatusstatus){System.out.printf( 訂單服務訂單[%s]狀態更新為 %s\n,orderId,status);}}// 支撐類classOrder{privateStringorderId;privateOrderInfoinfo;privateOrderStatusstatus;// 構造器與 getter/setter 省略...}classOrderInfo{privateStringsku;privateintquantity;privateStringaddress;privatedoubleweight;// 構造器與 getter 省略...}enumOrderStatus{CREATED,PAID,SHIPPED,COMPLETED,CANCELLED,FAILED}白話訂單服務只關心訂單的驗證與狀態變更不涉及支付或物流。3.2 子系統B支付服務 (PaymentService)publicclassPaymentService{publicPaymentResultprocessPayment(Orderorder,doubleamount){System.out.printf( 支付服務處理支付 | 訂單[%s] | 金額¥%.2f\n,order.getOrderId(),amount);System.out.printf( ? 支付服務支付成功\n);returnnewPaymentResult(true,PAYSystem.currentTimeMillis());}publicbooleanrefund(StringorderId,doubleamount){System.out.printf( 支付服務退款成功 | 訂單[%s]\n,orderId);returntrue;}}classPaymentResult{privatebooleansuccess;privateStringpaymentId;// 構造器...}3.3 子系統C庫存服務 (InventoryService)importjava.util.Map;importjava.util.concurrent.ConcurrentHashMap;publicclassInventoryService{privatefinalMapString,IntegerstockMapnewConcurrentHashMap();publicInventoryService(){stockMap.put(SKU001,100);stockMap.put(SKU002,50);stockMap.put(SKU003,200);}publicbooleancheckStock(Stringsku,intquantity){intcurrentstockMap.getOrDefault(sku,0);booleanokcurrentquantity;System.out.printf( 庫存服務檢查庫存 | SKU[%s] | %s\n,sku,ok?充足:不足);returnok;}publicvoiddeductStock(Stringsku,intquantity){stockMap.computeIfPresent(sku,(k,v)-v-quantity);System.out.printf( ? 庫存服務扣減成功 | SKU[%s] -%d\n,sku,quantity);}publicvoidrestoreStock(Stringsku,intquantity){stockMap.computeIfPresent(sku,(k,v)-vquantity);System.out.printf( ? 庫存服務恢復庫存 | SKU[%s] %d\n,sku,quantity);}}3.4 子系統D配送服務 (ShippingService)publicclassShippingService{publicdoublecalculateShippingFee(Stringaddress,doubleweight){doublefee10.0Math.max(0,weight-1)*5;System.out.printf( 配送服務運費 | 地址%s | 費用¥%.2f\n,address,fee);returnfee;}publicShipmentschedulePickup(Orderorder){StringtrackingNoTRKSystem.currentTimeMillis();System.out.printf( ? 配送服務已安排攬收 | 運單號%s\n,trackingNo);returnnewShipment(trackingNo,order.getOrderId());}}classShipment{/* trackingNo, orderId */}enumShipmentStatus{PENDING,PICKED_UP,IN_TRANSIT,DELIVERED}3.5 子系統E通知服務 (NotificationService)publicclassNotificationService{publicvoidsendOrderConfirmation(Orderorder,Stringuser){System.out.printf( 通知訂單確認 → 用戶[%s]\n,user);}publicvoidsendPaymentSuccess(Orderorder,Stringuser){System.out.printf( 通知支付成功 → 用戶[%s]\n,user);}publicvoidsendShipmentNotice(Orderorder,Stringuser){System.out.printf( 通知已發貨 → 用戶[%s]\n,user);}publicvoidsendOrderCancelled(Orderorder,Stringuser){System.out.printf( 通知訂單取消 → 用戶[%s]\n,user);}}3.6 外觀類物流訂單門面 (LogisticsOrderFacade)publicclassLogisticsOrderFacade{privatefinalOrderServiceorderServicenewOrderService();privatefinalPaymentServicepaymentServicenewPaymentService();privatefinalInventoryServiceinventoryServicenewInventoryService();privatefinalShippingServiceshippingServicenewShippingService();privatefinalNotificationServicenotificationServicenewNotificationService();publicOrderResultplaceOrder(OrderInfoorderInfo,Stringuser){System.out.println(\n 開始處理下單...);// 1. 校驗 庫存if(!orderService.validateOrder(orderInfo))returnOrderResult.failure(校驗失敗);if(!inventoryService.checkStock(orderInfo.getSku(),orderInfo.getQuantity()))returnOrderResult.failure(庫存不足);// 2. 創建訂單 通知OrderorderorderService.createOrder(orderInfo);notificationService.sendOrderConfirmation(order,user);// 3. 運費 支付doubleshippingFeeshippingService.calculateShippingFee(orderInfo.getAddress(),orderInfo.getWeight());doubletotal99.99*orderInfo.getQuantity()shippingFee;PaymentResultpaypaymentService.processPayment(order,total);if(!pay.isSuccess()){orderService.updateOrderStatus(order.getOrderId(),OrderStatus.FAILED);returnOrderResult.failure(支付失敗);}orderService.updateOrderStatus(order.getOrderId(),OrderStatus.PAID);notificationService.sendPaymentSuccess(order,user);// 4. 扣減庫存 配送inventoryService.deductStock(orderInfo.getSku(),orderInfo.getQuantity());ShipmentshipmentshippingService.schedulePickup(order);notificationService.sendShipmentNotice(order,user);orderService.updateOrderStatus(order.getOrderId(),OrderStatus.SHIPPED);System.out.println(? 下單完成);returnOrderResult.success(order.getOrderId(),pay.getPaymentId(),shipment.getTrackingNo());}publicbooleancancelOrder(StringorderId,Stringuser){System.out.println(\n 取消訂單...);paymentService.refund(orderId,99.99);orderService.updateOrderStatus(orderId,OrderStatus.CANCELLED);notificationService.sendOrderCancelled(newOrder(orderId,null),user);System.out.println(? 取消完成);returntrue;}}classOrderResult{/* success, orderId, paymentId, trackingNo, errorMsg */}白話外觀類的placeOrder就像前臺接待客戶說“我要下單”它就會按固定流程走完所有環節客戶完全不需知道背后有多少個部門在協作。3.7 客戶端測試publicclassClient{publicstaticvoidmain(String[]args){LogisticsOrderFacadefacadenewLogisticsOrderFacade();// 正常下單OrderResultr1facade.placeOrder(newOrderInfo(SKU001,2,北京市朝陽區,3.5),張三);if(r1.isSuccess()){System.out.printf(訂單號%s, 運單號%s\n,r1.getOrderId(),r1.getTrackingNo());}// 庫存不足OrderResultr2facade.placeOrder(newOrderInfo(SKU999,1000,上海市,1.0),李四);if(!r2.isSuccess())System.out.println(失敗原因r2.getErrorMsg());// 取消訂單facade.cancelOrder(r1.getOrderId(),張三);}}4. 運行結果 開始處理下單... 訂單服務校驗訂單信息... ? 庫存服務檢查庫存 | SKU[SKU001] | 充足 ? 訂單服務訂單創建成功 通知訂單確認 → 用戶[張三] 配送服務運費 | 費用¥22.50 支付服務支付成功 訂單服務狀態更新為 PAID 通知支付成功 → 用戶[張三] ? 庫存服務扣減成功 ? 配送服務已安排攬收 | 運單號TRK... 通知已發貨 → 用戶[張三] 訂單服務狀態更新為 SHIPPED ? 下單完成 訂單號..., 運單號TRK... 開始處理下單... 庫存服務檢查庫存 | SKU[SKU999] | 不足 失敗原因庫存不足 取消訂單... 支付服務退款成功 訂單服務狀態更新為 CANCELLED 通知訂單取消 → 用戶[張三] ? 取消完成5. 核心角色回顧角色職責對應代碼Facade統一入口封裝流程LogisticsOrderFacadeSubsystem獨立處理各自業務邏輯OrderService,PaymentService,InventoryService,ShippingService,NotificationService6. 外觀模式 vs 適配器模式對比項外觀模式適配器模式意圖簡化接口隱藏復雜性轉換接口讓不兼容的類協同工作關注點降低客戶端調用難度解決接口不兼容問題子系統感知子系統不知道外觀的存在適配器持有被適配者被適配者不知道適配器典型應用物流訂單門面、JdbcTemplateInputStreamReader、對接第三方快遞API一句話記憶外觀是“一鍵啟動”——把復雜流程變成一個方法適配器是“轉接頭”——把不兼容的接口轉成你想要的格式。7. 外觀模式的優缺點優點缺點簡化客戶端調用降低耦合可能成為“上帝類”所有請求都經過外觀保護子系統客戶端不會誤用危險方法新增子系統可能需要修改外觀類分層清晰可作為層間解耦手段高級用戶可能被隱藏了有用的子系統細節8. 六大設計原則體現原則體現單一職責外觀類只負責流程編排不實現具體業務開閉原則新增子系統可能需要修改外觀但可結合工廠緩解里氏替換子系統可替換升級不影響外觀依賴倒置客戶端依賴外觀抽象接口可進一步解耦接口隔離外觀提供精簡的高層接口避免“胖接口”迪米特法則客戶端只與外觀交互符合最少知識原則附 外觀模式 UML源碼物流訂單處理場景startuml title Java 23 種設計模式從踩坑到精通 footer 折哥 | 智能物流與Java實戰 1. 全局樣式配置 skinparam backgroundColor #FEFEFE skinparam shadowing false skinparam defaultFontName Microsoft YaHei skinparam classBorderColor #333333 skinparam classFontColor #1A1A1A skinparam classFontSize 14 skinparam noteFontSize 12 skinparam noteFontColor #555555 skinparam arrowColor #555555 skinparam classBackgroundColor #F9F9F9 2. 外觀類 - 物流訂單門面 class LogisticsOrderFacade { - orderService : OrderService - paymentService : PaymentService - inventoryService : InventoryService - shippingService : ShippingService - notificationService : NotificationService placeOrder(orderInfo) : OrderResult cancelOrder(orderId) : boolean } note right of LogisticsOrderFacade b外觀類物流訂單門面/b -- 為客戶端提供統一的下單入口 封裝內部多個子系統的復雜調用流程 客戶端無需了解內部細節 end note 3. 子系統類 class OrderService { validateOrder(info) : boolean createOrder(info) : Order updateOrderStatus(id, status) } note right of OrderService b子系統A訂單服務/b -- 負責訂單校驗、創建、狀態更新 end note class PaymentService { processPayment(order, amount) : PaymentResult refund(orderId, amount) : boolean } note right of PaymentService b子系統B支付服務/b -- 負責支付處理、退款 end note class InventoryService { checkStock(sku, quantity) : boolean deductStock(sku, quantity) restoreStock(sku, quantity) } note right of InventoryService b子系統C庫存服務/b -- 負責庫存檢查、扣減、恢復 end note class ShippingService { calculateShippingFee(address, weight) : double schedulePickup(order) : Shipment trackShipment(trackingNo) : ShipmentStatus } note right of ShippingService b子系統D配送服務/b -- 負責運費計算、攬收調度、物流跟蹤 end note class NotificationService { sendOrderConfirmation(order, user) sendPaymentSuccess(order, user) sendShipmentNotice(order, user) sendOrderCancelled(order, user) } note bottom of NotificationService b子系統E通知服務/b -- 負責短信、郵件、站內信通知 end note 4. 關系連線 LogisticsOrderFacade -- OrderService : 委托 LogisticsOrderFacade -- PaymentService : 委托 LogisticsOrderFacade -- InventoryService : 委托 LogisticsOrderFacade -- ShippingService : 委托 LogisticsOrderFacade -- NotificationService : 委托 enduml 《Java 23 種設計模式從踩坑到精通》快速導航開篇系列介紹與目錄正篇外觀模式 Facade —— 給復雜系統裝一個“一鍵啟動”當前番外 · 外觀模式 × 物流訂單處理你在這里創建型模式匯總結構型模式匯總行為型模式匯總 關注《Java 23 種設計模式從踩坑到精通》用 25 篇文章徹底吃透設計模式。福利預告全系列代碼及 UML 源碼將在完結時統一打包開放點擊「關注」「收藏」第一時間獲取。 除了設計模式我也在深挖智能物流實戰WMS、托盤調度、機器學習落地。歡迎點擊頭像看看專欄 《出版社物流WMS智能調度實戰》、《電商多平臺電子面單對接實戰》。技術相通思路可鑒。