天天看點

java設計模式分析之過濾器模式 、組合模式、外觀模式

一個優秀的android開源架構中往往會展現出很多Java設計模式的影子,了解設計模式有助于了解開源架構中的程式設計之美接下來我會将自己整理的對一些設計模式的了解記錄在這裡

若您對我的分享感興趣可以通路:java設計模式專欄

本篇記錄:過濾器模式 、組合模式、外觀模式

傳送門:  java設計模式分析及在android中的應用一

參考:

java設計模式之組合模式

從真實項目中摳出來的設計模式:過濾器模式

1、過濾器模式

介紹:

過濾器模式(Filter Pattern)或标準模式(Criteria Pattern)是一種結構型模式,這種模式允許開發人員使用不同的标準來過濾一組對象,通過邏輯運算以解耦的方式把它們連接配接起來,它可以結合多個标準來獲得單一标準

方法:

我們可以定義一系列規則。這些規則可以針對目标進行滿足自身規則的過濾

使用場景:

我們在給使用者做訂單催付通知的時候,會有這樣的一種場景,使用者在系統背景設定一組可以催付的規則,比如說訂單金額大于xx元,非黑名單使用者,來自哪個地區,已購買過某個商品等等這樣的條件,如果這時使用者下了一個訂單,那程式要判斷的就是看一下此訂單是否滿足這些規則中的某一個,如果滿足,我們給他發送催付通知,這種場景是很多做CRM的同學都會遇到的問題,那針對這種場景,如何更好的規劃業務邏輯呢?

如果是普通代碼實作:

我們可能會定義出一個删選類,由其負責對各種規則的篩選,那麼很多不清楚設計模式的人可能會秀出如下代碼:

var regulars = new List<Regulars>();

                 regulars.Add(new Regulars() { RegularID = 1, RegularName = "規則1", AnalysisConditons = "xxxx" });
                 regulars.Add(new Regulars() { RegularID = 1, RegularName = "規則2", AnalysisConditons = "xxxx" });
                 regulars.Add(new Regulars() { RegularID = 1, RegularName = "規則3", AnalysisConditons = "xxxx" });
                regulars.Add(new Regulars() { RegularID = 1, RegularName = "規則4", AnalysisConditons = "xxxx" });
   
                 var filters = FilterRegularID(regulars);
                 filters = FilterRegularName(filters);
                 filters = FilterCondtions(filters);
                //... 後續邏輯
          }
                static List<Regulars> FilterRegularID(List<Regulars> persons){
                //過濾 “姓名” 的邏輯
                 return null;
            }

                 static List<Regulars> FilterRegularName(List<Regulars> persons) {
               //過濾 “age” 的邏輯
                return null;
            }

      
    /// <summary>
     /// 各種催付規則
  /// </summary>      

}

    這種寫法簡單粗暴,維護起來也是一樣的簡單粗暴,上萬行的代碼就是這樣出來的,暫時看來已經實作了必須的功能,但是一旦後續一旦有規則的變更,相信即便是當時寫出這些代碼的人也會頭疼

設計模式告訴我們一個簡單的“開閉原則”,那就是追求最小化的修改代碼,這種場景有更好的優化政策嗎?

    當然有對應到設計模式上就是“過濾器模式”,專門針對這種場景的解決方案,一個次元一個類,然後通過邏輯運算類将他們進行組合

讓我們看看使用過濾器模式優化之後的代碼結構:

java設計模式分析之過濾器模式 、組合模式、外觀模式

    從上面這張圖紙中可以看到,我們抽象出了一個IFilter接口,然後提取成了三個子類每一個子類負責一個次元的過濾方法,然後實作了兩個邏輯運算類AND和OR子類Filter,用于動态的對上面的三個次元的過濾方法進行AND,OR邏輯運算

最後在我們的調用程式裡面,我們需要做的工作就簡單了,隻需要将每個次元的過濾條件,追加到邏輯運算類裡面就可以說笑呢功能了

and和or邏輯運算類的實作也比較簡單,兩個類裡面都維護了一個過濾器清單

  • and類隻需要周遊所有的過濾器,剔除需要過濾的原始對象集合中不符合規則的對象就可以了
  • or類可以使用一個hashMap,從需要過濾的原始對象集合中,選取符合某一個過濾條件的對象放入hashMap就可以了

使用泛型我們可以增加對多種過濾對象的支援

有沒有發現,如果後續有需求變更,比如說增加篩選的次元,我隻需要新增一個繼承IFilter的子類就搞定了,用戶端在調用的時候隻要在Filters集合中追加該篩選次元,是不是就OK了

是以這種模式幾乎達到了無代碼修改的地步,這就是設計模式給我們帶來的便捷

2、組合模式

可能我們看到組合這個詞,會下意識的和Java對象裡面的對象的組合聯系起來,但其實這兩者之間沒有聯系

java對象的組合指的是對象之間的協同工作,例如:

    一個人可以由大腦、軀幹、四肢等等對象組成那麼在People這個類中将head、trunk、limb等作為字段組合進來,讓這些對象協同完成一個人對象和以完成的工作,這就是java對象的組合

    而組合模式則主要是使用面向對象的思想來實作樹形結構的建構與處理,其中心思想是把一組相似的對象當做一個單一對象來進行處理

舉個例子:

windows系統中對于檔案夾管理就是典型的組合模式對于樹形結構的處理

再比如應用軟體中的菜單,辦公系統中的公司組織結構等等

組合模式的優點:

組合模式通過一種巧妙的設計方案使得使用者可以一緻性地處理整個樹形結構或者樹形結構的一部分,也可以一緻性地處理樹形結構中的葉子節點(不包含子節點的節點)和容器節點(包含子節點的節點)

接下來我們看看組合模式在實際場景中的應用

設計防毒軟體:

    該軟體既可以對某個檔案夾(Folder)殺毒,也可以對某個指定的檔案(File)進行殺毒。該防毒軟體還可以根據各類檔案的特點,為不同類型的檔案提供不同的殺毒方式,例如圖像檔案(ImageFile)和文本檔案(TextFile)的殺毒方式就有所差異。現需要提供該防毒軟體的整體架構設計方案。

     對于樹形結構,當容器對象(如檔案夾)的某一個方法被調用時,将周遊整個樹形結構,尋找也包含這個方法的成員對象(可以是容器對象,也可以是葉子對象)并調用執行,牽一而動百,其中使用了遞歸調用的機制來對整個結構進行處理。

    由于容器對象和葉子對象在功能上的差別,在使用這些對象的代碼中必須有差別地對待容器對象和葉子對象,而實際上大多數情況下我們希望一緻地處理它們,因為對于這些對象的差別對待将會使得程式非常複雜。

    組合模式為解決此類問題而誕生,它可以讓葉子對象和容器對象的使用具有一緻性

例如我們對防毒軟體的架構設計如下:

java設計模式分析之過濾器模式 、組合模式、外觀模式

AbstractFile充當抽象構件類,Folder充當容器構件類,ImageFile、TextFile和VideoFile充當葉子構件類

葉子類不支援檔案的增删操作,但是因為要進行統一封裝,保持對調用這的透明,是以也實作了增删操作,不過可以提供對應的錯誤提示和異常處理

    由于在本執行個體中使用了組合模式,在抽象構件類中聲明了所有方法,包括用于管理和通路子構件的方法,如add()方法和remove()方法等,是以在ImageFile等葉子構件類中實作這些方法時必須進行相應的異常處理或錯誤提示

在容器構件類Folder類的killVirus()方法中,Folder将遞歸調用其成員對象的killVirus()方法,進而實作對整個樹形結構的周遊。

如果需要更換操作節點,例如隻需對檔案夾“文本檔案”進行殺毒,用戶端代碼隻需進行簡單的修改即可

用戶端無須關心節點的層次結構,可以對所選節點進行統一處理,提高系統的靈活性

當然如果不想讓葉子節點實作不必要的方法,可以采用安全組合模式:

java設計模式分析之過濾器模式 、組合模式、外觀模式

    安全組合模式的缺點是不夠透明,因為葉子構件和容器構件具有不同的方法,且容器構件中那些用于管理成員對象的方法沒有在抽象構件類中定義,是以用戶端不能完全針對抽象程式設計,必須有差別地對待葉子構件和容器構件

    在實際應用中,安全組合模式的使用頻率也非常高,在Java AWT中使用的組合模式就是安全組合模式。

3、外觀模式(retrofit)

外觀模式(門面模式),這種模式隐藏了系統的複雜性,并向用戶端提供了一個用戶端可以通路系統的接口。來隐藏系統的複雜性

例如:圖檔加載架構Glide,我們隻需要使用其提供的簡單的操作接口就可以完成複雜的功能,Glide用這種模式隐藏了其背後進行的大量工作

關鍵之處在于:

在用戶端和複雜系統之間再加上一層,這一層将調用順序,依賴關系等處理好這也就是Glide提供給我們的接待員,這個接待員了解Glide在背後所做的各種工作,而隐藏了其中的複雜聯系,隻向我們提供了簡單的調用入口

缺點:

不符合開閉原則,如果想修改東西會比較麻煩,因為繼承重寫都不友善

原理圖如下:

java設計模式分析之過濾器模式 、組合模式、外觀模式

ShapeMaker就是外觀模式提供的接待員,這個接待員熟悉左邊複雜的shape系統的内部結構,然後隐藏了其中的各種實作,而僅僅隻向我們提供了簡單那的調用方法

優點是:簡單容易上手,并且比較安全

還有一個使用場景:在軟體的各個層次結構中,可以使用外觀模式定義系統中的每一層的入口