一文徹底搞明白外觀模式
本篇講解Java設計模式中的外觀模式,分為定義、模式應用前案例、結(jié)構(gòu)、模式應用后案例、適用場景、模式可能存在的困惑和本質(zhì)探討7個部分。
定義
外觀模式是為子系統(tǒng)中的一組接口提供一個一致的界面,外觀模式定義了一個高層接口,這個接口使得這一子系統(tǒng)更加容易使用。
在新的分類方式中,外觀模式被劃分至類之間的交互類別中,其簡化的是一個類與一組類之間的交互耦合問題。
模式應用前案例
在外觀模式中,列舉一個電商領域的案例。先來看一下未使用外觀模式前的代碼實現(xiàn)。
電商領域通常包括庫存子系統(tǒng)、支付子系統(tǒng)和物流子系統(tǒng),代碼如下。
public class InventorySystem {//庫存子系統(tǒng)
public void updateInventory(String product, int quantity) {
System.out.println("Updating inventory for " + product + ": " + quantity);
}
}
public class PaymentSystem {//支付子系統(tǒng)
public void processPayment(double amount) {
System.out.println("Processing payment: $" + amount);
}
}
public class ShippingSystem {//物流子系統(tǒng)
public void shipOrder(String address) {
System.out.println("Shipping order to address: " + address);
}
}
調(diào)用方代碼如下。
public class Client {//調(diào)用方代碼
public static void main(String[] args) {
InventorySystem inventory = new InventorySystem();
PaymentSystem payment = new PaymentSystem();
ShippingSystem shipping = new ShippingSystem();
inventory.updateInventory("Computer", 1);
payment.processPayment(1500);
shipping.shipOrder("123 Main Street");
}
}
在上述代碼中,不難發(fā)現(xiàn),調(diào)用方與各個子系統(tǒng)直接耦合,這樣主要帶來兩個問題。
一個問題是調(diào)用方需要知曉每一個子系統(tǒng)的細節(jié)。在某些情況下,這些子系統(tǒng)之間的關系也需要知曉。
另一個問題是如果子系統(tǒng)代碼發(fā)生變更,調(diào)用方代碼也需要受到關聯(lián)影響。
結(jié)構(gòu)
外觀模式的示例代碼如下。
public class SubSystemOne {
public void MethodOne() {
System.out.println("Called SubSystemComponentOne's methodOne()");
}
}
public class SubSystemTwo {
public void MethodTwo() {
System.out.println("Called SubSystemComponentTwo's MethodTwo()");
}
}
public class SubSystemThree {
public void MethodThree() {
System.out.println("Called SubSystemComponentThree's methodThree()");
}
}
public class SubSystemFour {
public void MethodFour() {
System.out.println("Called SubSystemComponentFour's MethodFour()");
}
}
public class Facade {
private SubSystemOne componentOne;
private SubSystemTwo componentTwo;
private SubSystemThree componentThree;
private SubSystemFour componentFour;
public Facade() {
componentOne = new SubSystemOne();
componentTwo = new SubSystemTwo();
componentThree = new SubSystemThree();
componentFour = new SubSystemFour();
}
public void MethodA() {
componentOne.MethodOne();
componentTwo.MethodTwo();
componentThree.MethodThree();
}
public void MethodB() {
componentTwo.MethodTwo();
componentThree.MethodThree();
componentFour.MethodFour();
}
}
public class Client {
public static void main(String[] args) {
Facade facade = new Facade();
// 客戶端只需要調(diào)用外觀類提供的接口
facade.MethodA();
facade.MethodB();
}
}
模式應用后案例
上述電商領域的案例,在應用外觀模式之后的代碼實現(xiàn)如下。
庫存子系統(tǒng)、支付子系統(tǒng)和物流子系統(tǒng)的代碼不變。
public class InventorySystem {//庫存子系統(tǒng)
public void updateInventory(String product, int quantity) {
System.out.println("Updating inventory for " + product + ": " + quantity);
}
}
public class PaymentSystem {//支付子系統(tǒng)
public void processPayment(double amount) {
System.out.println("Processing payment: $" + amount);
}
}
public class ShippingSystem {//物流子系統(tǒng)
public void shipOrder(String address) {
System.out.println("Shipping order to address: " + address);
}
}
按照外觀模式,增加了一個外觀類。
public class OrderFacade {//訂單外觀類
private final InventorySystem inventory;
private final PaymentSystem payment;
private final ShippingSystem shipping;
public OrderFacade() {
this.inventory = new InventorySystem();
this.payment= new PaymentSystem();
this.shipping= new ShippingSystem();
}
//提供一個簡化方法來處理整個訂單流程
public void placeOrder(String product, int quantity,double amount,String address){
this.inventory.updateInventory(product,quantity);
this.payment.processPayment(amount);
this.shipping.shipOrder(address);
}
}
最后,調(diào)用方代碼修改如下。
public class Client {
public static void main(String[] args) {
//使用外觀模式進行下單操作
OrderFacade facade= new OrderFacade();
facade.placeOrder("Computer", 1, 1500.00,"123 Main Street");
}
}
可以看到,代碼的復雜性已經(jīng)挪到外觀類中實現(xiàn),調(diào)用方代碼變得非常簡潔清晰。
適用場景
外觀模式適用于以下場景:
1、多個子系統(tǒng)或接口需要通過一定的交互共同為調(diào)用方服務,如果希望子系統(tǒng)后續(xù)可以相對調(diào)用方獨立進行演進,可以考慮外觀模式
2、需求實現(xiàn)新功能時,需要依賴企業(yè)中的遺留系統(tǒng)的功能。由于遺留系統(tǒng)通常后續(xù)會安排下線。此時就不建議將遺留系統(tǒng)的接口直接對調(diào)用方暴露,而是在一個外觀類中封裝新增加的功能和遺留系統(tǒng)功能
模式可能存在的困惑
困惑1:外觀模式定義中提到的“界面”,具體是什么含義?
在外觀模式中,多個子系統(tǒng)屬于一個大的系統(tǒng)。界面可以理解為這個大系統(tǒng)對外暴露的契約接口。調(diào)用方只能通過界面來與系統(tǒng)進行交互。
本質(zhì)
對于一個系統(tǒng)來講,對外暴露清晰簡潔的接口是非常有必要的。這不僅可以節(jié)省與調(diào)用方的溝通成本,也可以與調(diào)用方相對解耦,以便后續(xù)獨立進行演進。
在系統(tǒng)建設初期,和調(diào)用方會制定契約接口。但是隨著系統(tǒng)功能越來越多,經(jīng)常會發(fā)現(xiàn)調(diào)用方需要依賴的接口越來越多,此時就可以將相互有關系的接口,再通過外觀類這一層進行再封裝,始終保持對外的簡潔性。
此外,在外觀模式下,外觀類通常并不新增功能,僅僅是封裝已有多個子系統(tǒng)的交互關系。