本文源碼: GitHub·點這裡 || GitEE·點這裡
一、生活場景
1、場景描述
在移動網際網路沒有普及之前,去飯店吃飯的流程大緻如下:選座位,排隊,點菜,結賬。後來移動網際網路普及,通過手機APP就可以操作這些流程,非常的友善快捷:通過手機可以知道某飯店是不是還有空位,到了飯店之後直接入座,然後通過手機點菜,結賬,中間省去了很多繁瑣的流程。
2、代碼圖解
3、代碼實作
/**
* 外觀模式描述飯店就餐流程
*/
public class C01_InScene {
public static void main(String[] args) {
EatAppFacade eatAppFacade = new EatAppFacade () ;
eatAppFacade.dining();
}
}
// 預定
class Booking {
private static Booking booking = new Booking() ;
public static Booking getInstance (){
return booking ;
}
public void bookPlace (){
System.out.println("位置預定...");
}
}
// 點餐
class TakeOrder {
private static TakeOrder takeOrder = new TakeOrder ();
public static TakeOrder getInstance (){
return takeOrder ;
}
public void orderDishes (){
System.out.println("點餐...");
}
}
// 付款
class Payment {
private static Payment payment = new Payment () ;
public static Payment getInstance (){
return payment ;
}
public void payMoney (){
System.out.println("結賬...");
}
}
// 點餐APP
class EatAppFacade {
private Booking booking ;
private TakeOrder takeOrder ;
private Payment payment ;
public EatAppFacade (){
this.booking = Booking.getInstance() ;
this.takeOrder = TakeOrder.getInstance() ;
this.payment = Payment.getInstance() ;
}
// 就餐流程
public void dining (){
booking.bookPlace();
takeOrder.orderDishes();
payment.payMoney();
}
}
二、外觀設計模式
1、基本簡介
外觀模式是對象的結構模式,用戶端與一個子系統的通信必須通過一個統一的外觀對象進行。外觀模式提供一個高層次的接口,使得子系統更易于使用。
2、模式圖解
3、核心角色
- 外觀角色
用戶端可以調用這個角色的方法。此角色具有相關的子子產品的功能。在正常情況下,本角色會将所有從用戶端發來的請求委派到相應的子系統去。
- 子子產品角色
可以同時有一個或者多個子子產品。每個子子產品都不是一個單獨的類,而是一個類的集合(如上面的子子產品就是由ModuleA、ModuleB、ModuleC三個類組合而成)。每個子系統都可以被用戶端直接調用,或者被外觀角色調用。子子產品并不知道外觀的存在,對于子子產品而言,外觀角色僅僅是另外一個用戶端。
- 用戶端角色
外觀對象功能的調用者。
4、源代碼實作
public class C02_Facade {
public static void main(String[] args) {
Facade facade = new Facade();
facade.clientNeed1();
facade.clientNeed2();
}
}
class ModuleA {
public void testA (){
System.out.println("ModuleA.testA()");
}
}
class ModuleB {
public void testB (){
System.out.println("ModuleB.testB()");
}
}
class ModuleC {
public void testC (){
System.out.println("ModuleC.testC()");
}
}
class Facade {
/**
* 客戶需求1
*/
public void clientNeed1 (){
ModuleA moduleA = new ModuleA();
moduleA.testA();
ModuleB moduleB = new ModuleB();
moduleB.testB();
}
/**
* 客戶需求1
*/
public void clientNeed2 (){
ModuleB moduleB = new ModuleB();
moduleB.testB();
ModuleC moduleC = new ModuleC();
moduleC.testC();
}
}
三、Mybatis應用場景
1、使用場景
- org.apache.ibatis.session.Configuration
- org.apache.ibatis.reflection.MetaObject
Configuration 建立 MetaObject 的時候。
2、Configuration源碼
public class Configuration {
protected ObjectFactory objectFactory;
protected ObjectWrapperFactory objectWrapperFactory;
public Configuration() {
this.objectFactory = new DefaultObjectFactory();
this.objectWrapperFactory = new DefaultObjectWrapperFactory();
}
public MetaObject newMetaObject(Object object) {
return MetaObject.forObject(object, this.objectFactory, this.objectWrapperFactory);
}
// ... 省去其他源碼
}
3、MetaObject 源碼
public static MetaObject forObject(Object object,
ObjectFactory objectFactory,
ObjectWrapperFactory objectWrapperFactory) {
return object == null ?
SystemMetaObject.NULL_META_OBJECT :
new MetaObject(object, objectFactory, objectWrapperFactory);
}
四、優缺點總結
松散了用戶端與子子產品的耦合關系,使子子產品功能的調用更加簡單。通過合理使用Facade,可以更好地劃分通路的層次。有些方法是對系統外的,有些方法是系統内部使用的,把需要暴露給外部的功能集中到門面中。如果過多的使用外觀模式,會讓子子產品功能的維護變的複雜,一個功能方法改變,會牽扯到多個外觀對象的改變。
五、源代碼位址
GitHub·位址
https://github.com/cicadasmile/model-arithmetic-parent
GitEE·位址
https://gitee.com/cicadasmile/model-arithmetic-parent