设计模式(12):外观模式FACADE

外观模式

意图

为子系统中的一组接口提供一个一致的界面,Facade模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。


使用场景

以下情况使用Facade模式:

  • 当你要为一个复杂子系统提供一个简单接口时。子系统往往因为不断演化而变得越来越复杂。大多数模式使用时都会产生更多更小的类。这使得子系统更具可重用性,也更容易对子系统进行定制,但这也给那些不需要定制子系统的用户带来一些使用上的困难。Facade可以提供一个简单的缺省视图,这一视图对大多数用户来说已经足够,而那些需要更多的可定制性的用户可以越过Facade层。
  • 客户程序与抽象类的实现部分之间存在着很大的依赖性。引入Facade将这个子系统与客户以及其他的子系统分离,可以提高子系统的独立性和可移植性。
  • 当你需要构建一个层次结构的子系统时,使用Facade模式定义子系统中每层的入口点。如果子系统之间是相互依赖的,你可以让它们仅通过Facade进行通讯,从而简化了它们之间的依赖关系。

结构

外观模式结构如下
ShowImage

  • Facade

    – 知道哪些子系统类负责处理请求。

    – 将客户的请求代理给适当的子系统对象。

  • Subsystem

    – 实现子系统的功能。

    – 处理由Facade对象指派的任务。

    – 没有Facade的任何相关信息;即没有指向Facade对象的引用。

协作

客户程序通过发送请求给Facade的方式与子系统通讯,Facade将这些消息转发给适当的子系统对象。尽管是子系统中的有关对象在做实际工作,但Facade模式本身也必须将它的接口转换成子系统的接口。使用Facade的客户程序不需要直接访问子系统对象。

优点

  • 它对客户屏蔽子系统组件,因而减少了客户处理的对象的数目并使得子系统使用起来更加方便。
  • 它实现了子系统与客户之间的松耦合关系,而子系统内部的功能组件往往是紧耦合的。

    松耦合关系使得子系统的组件变化不会影响到它的客户。Facade模式有助于建立层次结构系
    统,也有助于对对象之间的依赖关系分层。Facade模式可以消除复杂的循环依赖关系。这一
    点在客户程序与子系统是分别实现的时候尤为重要。

    在大型软件系统中降低编译依赖性至关重要。在子系统类改变时,希望尽量减少重编译工作以节省时间。用Facade可以降低编译依赖性,限制重要系统中较小的变化所需的重编译工作。Facade模式同样也有利于简化系统在不同平台之间的移植过程,因为编译一个子系统一般不需要编译所有其他的子系统。
  • 如果应用需要,可以使用子系统类。因此你可以在系统易用性和通用性之间加以选择。

外观模式实现(Implement)

案例

现在在线商城要实现下单功能,下单功能依赖于仓储服务子系统,支付服务子系统以及物流服务子系统三个子系统的功能,但是用户并不需要知道他们具体是怎么运作的,用户只关心下单是否成功,这里就可以用外观模式来解决。

代码实现

产品Product类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class Product {
private int productId;
private String productName;
public Product(int productId, String productName) {
this.productId = productId;
this.productName = productName;
}
public int getProductId() {
return productId;
}
public void setProductId(int productId) {
this.productId = productId;
}
public String getProductName() {
return productName;
}
public void setProductName(String productName) {
this.productName = productName;
}
}

下单服务接口

1
2
3
public interface OrderServiceFacade {
boolean order(int productId, String productName);
}

仓储服务子系统

1
2
3
4
5
6
7
public class WarehouseService {
public boolean isAvailable(Product product) {
//check whether product in warehouse is available
System.out.println("Product-->" + product.getProductName() + " in No.1 warehouse is available...");
return true;
}
}

支付服务子系统

1
2
3
4
5
6
7
public class PaymentService {
public boolean isPaymentSuccessful() {
//check whether payment is successful
System.out.println("Payment is successful...");
return true;
}
}

物流服务子系统

1
2
3
4
5
6
public class ShippingService {
public void shipProduct(Product product) {
//Ship the product
System.out.println("Begin to ship the product...");
}
}

下单服务具体实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class OrderService implements OrderServiceFacade {
private WarehouseService warehouseService;
private ShippingService shippingService;
private PaymentService paymentService;
public OrderService(WarehouseService warehouseService, ShippingService shippingService, PaymentService paymentService) {
this.warehouseService = warehouseService;
this.shippingService = shippingService;
this.paymentService = paymentService;
}
@Override
public boolean order(int productId, String productName) {
boolean isOrderSuccessful = false;
Product product = new Product(productId, productName);
if (warehouseService.isAvailable(product) && paymentService.isPaymentSuccessful()) {
shippingService.shipProduct(product);
System.out.println("ProductName : "
+ product.getProductName()
+ ", ProductId : "
+ product.getProductId()
+ ", is shipped...");
System.out.println("Order is successful...");
isOrderSuccessful = true;
}
return isOrderSuccessful;
}
}

下单书籍测试类

1
2
3
4
5
6
7
8
public class FacadeDemoTest {
@Test
public void orderBookTest() {
OrderService orderService = new OrderService(new WarehouseService(), new ShippingService(), new PaymentService());
boolean orderResult = orderService.order(100001, "Thinking In Java");
assertThat(orderResult, is(true));
}
}

用户并不需要了解子系统的详细结构,只需要调用orderService的order方法就可以完成下单。

总结

外观模式是一种使用频率非常高的结构型设计模式,它通过引入一个外观角色来简化客户端与子系统之间的交互,为复杂的子系统调用提供一个统一的入口,降低子系统与客户端的耦合度,且客户端调用非常方便。

参考代码

------ 本文结束 ------

版权声明


BillyYccc's blog by Billy Yuan is licensed under a Creative Commons BY-NC-SA 4.0 International License.
本文原创于BillyYccc's Blog,转载请注明原作者及出处!