(十一)外觀模式詳解(Service第三者插足,讓action與dao分手) .

  各位好,LZ今天給各位分享一個不太熟悉的面孔,但倒是咱們最常用的設計模式,外觀模式。java

  定義:外觀模式是軟件工程中經常使用的一種軟件設計模式。它爲子系統中的一組接口提供一個統一的高層接口。這一接口使得子系統更加容易使用。android

   該定義引自百度百科,它的表現很簡單,將一系列子接口的功能進行整理,從而產生一個更高層的接口。web

   相信作JAVA的各位大部分是WEB開發,那麼確定都對XXXDao,XXXService很是熟悉了,這顯然和外觀模式有一腿。固然,還有一大部分是android開發,LZ沒接觸過android開發,可是LZ大膽的想象,在移動領域的JAVA開發,應該也有相似的狀況發生。編程

   接下來,咱們來看看外觀模式的標準類圖。設計模式


    上述即是外觀模式的類圖,它主要由兩部分組成,一部分是子系統(包括接口,實現類,等等),一部分是外觀接口和實現類,外觀接口負責提供客戶端定製的服務,外觀實現則負責組合子系統中的各個類和接口完成這些服務,外觀接口則是提供給客戶端使用的,這樣就解除了客戶端與子系統的依賴,而讓客戶端只依賴於外觀接口,這是一個優秀的解耦實踐。架構

    下面LZ依然使用JAVA代碼將上述的類圖詮釋出來,咱們來直觀的看看外觀模式的實現方式。首先是咱們的子系統,它包括三個接口,三個實現,LZ這裏一併給出。eclipse

package com.facade;  
  
public interface Sub1 {  
  
    void function1();  
      
}
package com.facade;  
  
public interface Sub2 {  
  
    void function2();  
      
}
package com.facade;  
  
public interface Sub3 {  
  
    void function3();  
      
}
package com.facade;  
  
public class Sub1Impl implements Sub1{  
  
    public void function1() {  
        System.out.println("子系統中Sub1接口的功能");  
    }  
  
}
package com.facade;  
  
public class Sub2Impl implements Sub2{  
  
    public void function2() {  
        System.out.println("子系統中Sub2接口的功能");  
    }  
  
}
package com.facade;  
  
public class Sub3Impl implements Sub3{  
  
    public void function3() {  
        System.out.println("子系統中Sub3接口的功能");  
    }  
  
}

   以上即是咱們模擬出的一個子系統,那麼如今即是咱們最重要的接口出場的時候了,LZ給出Facade以及它的簡單實現。工具

package com.facade;  
  
public interface Facade {  
      
    /*  下面隨便組裝幾個功能  */  
      
    void function12();  
      
    void function23();  
      
    void function123();  
      
}
package com.facade;  
  
public class FacadeImpl implements Facade{  
  
    private Sub1 sub1;  
      
    private Sub2 sub2;  
      
    private Sub3 sub3;  
      
    public FacadeImpl() {  
        super();  
        this.sub1 = new Sub1Impl();  
        this.sub2 = new Sub2Impl();  
        this.sub3 = new Sub3Impl();  
    }  
  
    public FacadeImpl(Sub1 sub1, Sub2 sub2, Sub3 sub3) {  
        super();  
        this.sub1 = sub1;  
        this.sub2 = sub2;  
        this.sub3 = sub3;  
    }  
  
    public void function12() {  
        sub1.function1();  
        sub2.function2();  
    }  
  
    public void function23() {  
        sub2.function2();  
        sub3.function3();  
    }  
  
    public void function123() {  
        sub1.function1();  
        sub2.function2();  
        sub3.function3();  
    }  
  
}

   以上即是咱們的外觀接口和實現類,它當中的功能通常是根據是客戶端的須要定製的,將客戶端的一個完整功能做爲一個行爲,而後調用子系統完成。下面咱們看看客戶端的調用。this

package com.facade;  
  
public class Client {  
  
    public static void main(String[] args) {  
        Facade facade = new FacadeImpl();  
        facade.function12();  
        System.out.println("-------------------------");  
        facade.function23();  
        System.out.println("-------------------------");  
        facade.function123();  
          
        /*  以上爲使用了外觀模式的調用方式,如下爲原始方式   */  
          
        System.out.println("-------------如下原始方式--------------");  
        Sub1 sub1 = new Sub1Impl();  
        Sub2 sub2 = new Sub2Impl();  
        Sub3 sub3 = new Sub3Impl();  
        sub1.function1();  
        sub2.function2();  
        System.out.println("-------------------------");  
        sub2.function2();  
        sub3.function3();  
        System.out.println("-------------------------");  
        sub1.function1();  
        sub2.function2();  
        sub3.function3();  
    }  
      
}

   LZ在下面還給出了原始的調用方式,能夠看出在外觀模式的做用下,咱們客戶端只依賴外觀一個接口,而在原始的方式下,咱們的客戶端依賴於整個子系統,因此外觀模式主要解決的是類之間的耦合過於複雜。spa

   附上LZ運行結果。

   以上即是標準的外觀模式展示,LZ下面再給出須要知曉的幾點。

    1,實際使用當中,接口並非必須的,雖然說根據依賴倒置原則,不管是處於高層的外觀層,仍是處於底層的子系統,都應該依賴於抽象,可是這會倒置子系統的每個實現都要對應一個接口,從而致使系統的複雜性增長,因此這樣作並非必須的。

    2,外觀接口當中並不必定是子系統中某幾個功能的組合,也能夠是將子系統中某一個接口的某一功能單獨暴露給客戶端。

    3,外觀接口若是須要暴露給客戶端不少的功能的話,能夠將外觀接口拆分爲若干個外觀接口,如此便會造成一層外觀層。

    上述LZ給出的第三點,即是爲了引出咱們標題當中的service,相信各位作過web開發的都見過咱們項目中不少的service和dao(注:小型項目或許不須要service這一層),這一層service層,有一個很是重要的做用,就是爲了方便咱們管理項目中與業務邏輯相關的事物,而service層,實際上是給咱們的事務管理器提供了一個能夠方便的配置切入點的事物管理層。

    除了上述這個重要的功能外,service層同時也是組合dao層暴露給action的功能,dao層的各個類只是簡單的數據操做對象,它們不具備業務邏輯,而賦予了它們業務邏輯方便action調用的功臣,正是service這一層。各位能夠想象一下,假設沒有service這一層,你的action當中有不少功能須要依賴多少個dao才能夠完成工做。

    同時在WEB項目中,有的項目會抽象出一層service接口和一層dao接口,這是爲了下降客戶端(這裏的客戶端能夠認爲是action)與業務實現細節以及service外觀層與數據操做實現細節的耦合,而有的項目則沒有抽象層,這也並不是就是不合適的。

   首先添加抽象層會大大的加重項目的類文件數量,從而使項目的複雜性增長,並且在項目剛進入開發的時候,每每接口是不穩定的,由於咱們常常會須要要給某一個service添加一個方法,而爲了將方法暴露給客戶端(即action),咱們必須將該方法添加到對應的接口當中。

   因此針對這一狀況,咱們更好的作法是等到接口行爲相對穩定時,再考慮是否要重構去添加抽象的接口,並且如今的IDE工具都在必定程度上對重構進行了支持,好比eclipse就能夠直接導出一個類的接口,因此咱們徹底能夠在須要時快速的給項目添加抽象的接口層。

   相比起觀察者模式,適配器模式等適合小規模使用的設計模式,外觀模式更多的是大範圍的使用,它會是不少時候支撐咱們整個架構的設計思路。

    鑑於此,LZ此處再也不給出具體的service和dao的示例,各位的項目中處處都充斥着這種例子。

     若是形象的去形容外觀模式在WEB中的應用,能夠說它讓action和dao分了手,而插入了一個第三者service,斷開了action與dao的耦合,轉而使用更高層的service。

    這裏須要提醒各位的是,外觀模式並非簡單的使用組合將功能組合起來,也就是說它的重點不在組合功能,而在於製做一個對外暴露的外觀。它通常是用來將一個子系統(注意,是一個子系統,也就是說外觀並非簡單的幾個類的組合就是外觀模式了)的功能進行調配,暴露給客戶端一個外部的表象,使得客戶端與子系統斷開依賴關係。

    因爲外觀模式屬於一種「大」模式,因此咱們平時不多會接觸到,可是有不少技術的應用,其實都有着外觀模式的影子。

     好比webservice,它是給一個WEB應用提供一個外觀,讓客戶端能夠調用一些接口去使用WEB應用當中的一些功能或者說服務。再好比API,中文名稱應用程序接口,它其實也能夠看作是給底層的操做系統作了一層外觀,使程序猿在編程的時候能夠直接使用外觀提供的接口,從而間接的指揮操做系統完成一些事情。

    本次外觀模式的分享,LZ沒有像以前同樣寫一堆示例代碼給各位看,更多的是在討論外觀模式的應用場景和應用範圍,但願各位看完以後對外觀模式有一個宏觀的認識,而不是僅限於代碼層次的理解。

    好了,本次外觀模式的分享就到此結束了,謝謝各位的收看,下期再見。

                    下期預告,命令模式。

相關文章
相關標籤/搜索