首頁  >  文章  >  Java  >  工作五年了,居然還不懂 門面模式!

工作五年了,居然還不懂 門面模式!

Java后端技术全栈
Java后端技术全栈轉載
2023-08-28 15:11:34883瀏覽


好啦,進入我們的主題,今天我給大家分享設計模式中的門面模式用貼切的生活故事,以及真實專案場景來講設計模式,最後用一句話來總結這個設計模式。

故事

#開發的朋友都知道,後端開發通常都是:

controller---servie---dao/mapper/repository

但是,我問過很多人,熟悉門面模式不?有的工作五年了都不知道。

今天老田,就帶你來看看門面模式。

門面模式概述

#門面模式(Facade Pattern)又叫作外觀模式,提供了一個統一的接口,用來存取子系統中的一群接口。其主要特徵是定義了一個高層接口,讓子系統更容易使用,屬於結構型設計模式。

英文:

Provide a unified interface to a set of interfaces in asubsystem.Facade defines a higher-level interface that makes thesubsystem easier to use.

其實,在日常編碼工作中,我們都在有意無意地大量使用門面模式。但凡只要高層模組需要調度多個子系統(2個以上類對象),我們都會自覺地創建一個新類封裝這些子系統,提供精簡的接口,讓高層模組可以更容易地間接調用這些子系統的功能。

生活中的案例

#關於門面模式,在生活中的案例,非常多。

案例1:去銀行辦理業務,有個前台接待你,然後,這個前台會問你需要辦什麼業務,他會一個一個帶你辦理,這樣我們就不需要到處亂串、到處找對應業務視窗了。這個前台人員就相當於門面模式。

案例2:我們蓋房子,如果沒有包工頭的話,那就是你自己要去找水泥工,電工、裝潢工等。但如果有了包工頭,這些活你都不用乾了,直接跟包工頭說,需要電工來把線路搞好。這個包工頭就可以理解為門面模式。

案例3:我們後端開發的controller,也可以理解為門面模式,比如說獲取用戶帳戶信息,先查UserService獲取用戶信息,然後查UserAccountService使用者帳戶資訊。

門面模式適用場景

#在軟體系統中,門面模式適用於下列應用情境。

  • 為一個複雜的模組或子系統提供一個簡潔的供外界存取的介面。
  • 希望提高子系統的獨立性時。
  • 當子系統由於不可避免的暫時原因導致可能存在Bug或性能相關問題時,可以透過門面模式提供一個高層接口,隔離客戶端與子系統的直接交互,預防代碼污染。

門面模式通用寫入法

#還是使用程式碼來實作一個簡單的門面模式,因為咱們最喜歡的就是從demo開始。

業務場景:現在需要呼叫三個service的各自的方法:

public class ServiceA {
    public void doA(){
        System.out.println("do ServiceA");
    }
}
public class ServiceB {
    public void doB(){
        System.out.println("do ServiceB");
    }
}

public class ServiceC {
    public void doC(){
        System.out.println("do ServiceC");
    }
}

在沒有引入門面模式的時候,客戶端是這麼調用的:

public class Client {
    public static void main(String[] args) {
        ServiceA serviceA=new ServiceA();
        ServiceB serviceB=new ServiceB();
        ServiceC serviceC=new ServiceC();

        serviceA.doA();
        serviceB.doB();
        serviceC.doC();
    }
}

每次,客戶端自己都需要建立很多service對象,如果涉及到有很多個service,那這程式碼不是很尷尬嗎?會出現大量重複性的程式碼。

運行結果

do ServiceA
do ServiceB
do ServiceC

下面我們就來加入門面模式

public class Facade {
    //是不是很像我们controller里注入各种service?
    private ServiceA serviceA = new ServiceA();
    private ServiceB serviceB = new ServiceB();
    private ServiceC serviceC = new ServiceC();

    public void doA() {
        serviceA.doA();
    }

    public void doB() {
        serviceB.doB();
    }

    public void doC() {
        serviceC.doC();
    }
}

客戶端變成了:

public class Client {
    public static void main(String[] args) {
        //轻轻松松的搞定,只需要创建门面这个对象即可
        Facade facade=new Facade();
        facade.doA();
        facade.doB();
        facade.doC();
    }
}

運行結果:

do ServiceA
do ServiceB
do ServiceC

門面模式UML圖


工作五年了,居然還不懂 門面模式!

結合這個UML圖,在回顧銀行前台人員和包工頭的案例,就更輕鬆的理解門面模式了。

門面模式中的角色

由上圖可以看到,門面模式主要包含2個角色。

  • 外觀角色(Facade):也叫作門面角色,是系統對外的統一介面。
  • 子系統角色(Service):可以同時有一個或多個Service。每個Service都不是單獨的類,而是一個類別的集合。 Service們並不知道Facade的存在,對Service們而言,Facade 只是另一個客戶端而已(即FacadeServiceAServiceBServiceC透明)。

門面模式的擴充

##● 減少系統的相互依賴 想想看,如果我們不使用門面模式,外界訪問直接深入到子系統內部,相互之間是一種強耦合關係,你死我就死,你活我才能活,這樣的強依賴是系統設計所不能接受的,門面模式的出現就很好地解決了這個問題,所有的依賴都是對門面物件的依賴,與子系統無關。

###● 提高了靈活性   依賴減少了,靈活性自然提高了。不管子系統內部如何變化,只要不影響門面對象,任你自由活動。 ###

● 提高安全性   想让你访问子系统的哪些业务就开通哪些逻辑,不在门面上开通的方法,你休想访问到 。

缺点

  • 当增加子系统和扩展子系统行为时,可能容易带来未知风险。
  • 不符合开闭原则。
  • 某些情况下,可能违背单一职责原则

大神们是如何使用的

Spring中也是有大量使用到门面模式,比如说

org.springframework.jdbc.support.JdbcUtils

再来看看其中的方法

public static void closeConnection(@Nullable Connection con) {
    con.close();
}
public static Object extractDatabaseMetaData(DataSource dataSource, DatabaseMetaDataCallback action)
   throws MetaDataAccessException {
    Connection con = null;
  try {
   con = DataSourceUtils.getConnection(dataSource);
   DatabaseMetaData metaData = con.getMetaData();
   if (metaData == null) {
      //.....
   }
   return action.processMetaData(metaData);
  }
}
......

都是给我封装好了方法,对于我们开发者来说,我只面向JdbcUtils这一个类就好了,我不用去管ConnectionResultSet等是怎么创建的,需要的时候,我调用JdbcUtils的对应方法即可获得对应的对象。

Mybatis中也是用到了门面模式,比如:

org.apache.ibatis.session.Configuration

Configuration中以new开头的方法,比如:

public Executor newExecutor(Transaction transaction) {
    return newExecutor(transaction, defaultExecutorType);
}
public MetaObject newMetaObject(Object object) {
    return MetaObject.forObject(object, objectFactory, objectWrapperFactory, reflectorFactory);
}

public ParameterHandler newParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
    ...
    return parameterHandler;
}

public ResultSetHandler newResultSetHandler(Executor executor, MappedStatement mappedStatement, RowBounds rowBounds, ParameterHandler parameterHandler,
      ResultHandler resultHandler, BoundSql boundSql) {
   ...
    return resultSetHandler;
}

public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement){
   ...
}

对于调用这些方法的地方,他并不知道是怎么new出来的对象,只管使用就行了。

Tomcat中也有门面模式,比如:

org.apache.catalina.connector.RequestFacade

从名字就知道它用了门面模式。它封装了非常多的request操作,也整合了很多servlet-api以外的内容,给用户使用提供了很大便捷。同样,Tomcat针对ResponseSession也封装了对应的ResponseFacade类和StandardSessionFacade类,感兴趣的小伙伴可以深入了解一下。

PS:基本上所有以Facade结尾的类,都是使用到了门面模式。

參考:tom的設計模式課程

總結

##好了,關於門面模式就分享這麼多,看完本文是不是覺得門面模式其實很簡單的,另外在工作也可以考慮是不是可以把它用上,同時,面試的時候也可以用來吹吹。

以上是工作五年了,居然還不懂 門面模式!的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:Java后端技术全栈。如有侵權,請聯絡admin@php.cn刪除

相關文章

看更多