1.政策模式
定義一系列算法,把他們獨立封裝起來,并且這些算法之間可以互相替換。政策模式主要是管理一堆有共性的算法,政策模式讓算法獨立于使用它的客戶而變化,用戶端可以根據需要,很快切換這些算法,并且保持可擴充性。
政策模式的本質:分離算法,選擇實作。
2.UML類圖
政策模式結構中包括三種角色:
- 政策(Strategy):政策是一個接口,該接口定義若幹個算法辨別,即定義了若幹個抽象方法。
- 具體政策(ConcreteStrategy):具體政策是實作政策接口的類,具體政策實作政策接口所定義的抽象方法,即給出算法辨別的具體算法。
- 上下文(Context):上下文是依賴于政策接口的類,即上下文包含有政策聲明的變量。上下文中提供一個方法,該方法委托政策變量調用具體政策所實作的政策接口中的方法。
3.舉例說明
就拿程式員舉例吧,假如現在我要寫一個程式,我們可以使用java、php。那到底使用哪種語言呢?使用我們的簡單工廠模式完全可以解決這個問題
1、抽象語言類
public interface CodeLanguage {
void useLanguage();
}
2、具體語言類
public class CodeJava implements CodeLanguage {
@Override
public void useLanguage() {
System.out.println("使用Java語言程式設計");
}
}
public class CodePhp implements CodeLanguage {
@Override
public void useLanguage() {
System.out.println("使用Php語言程式設計");
}
}
3、工廠類
public class LanguageFactory {
public static CodeLanguage getLanguage(String type){
CodeLanguage codeLanguage=null;
switch (type){
case "java":
codeLanguage=new CodeJava();
break;
case "php":
codeLanguage=new CodePhp();
break;
}
return codeLanguage;
}
}
雖然問題解決了,但正如我們所說的簡單工廠模式的缺點一樣:
- 工廠類負責所有對象的建立邏輯,該類出問題整個系統無法運作。
- 系統擴充困難,一旦添加新産品就不得不修改工廠方法。
-
由于使用了靜态工廠方法,是以工廠角色無法形成基于繼承的等級結構。
假如我們又要增加使用python語言,那麼我們除了增加相應的語言類,還要修改工廠類,很明顯這不是最佳的方法,而政策模式便是最好的選擇。根據政策模式的定義,政策模式主要是管理一堆有共性的算法,這些算法封裝到一個個的具體算法類中,而這些具體算法類都是一個抽象算法類的子類。換言之,這些具體算法類均有統一的接口,根據“裡氏代換原則”和面向對象的多态性,用戶端可以選擇使用任何一個具體算法類,并隻需要維持一個資料類型是抽象算法類的對象。對比簡單工廠模式,我們發現,簡單工廠模式是利用工廠類根據參數來動态的生成具體産品類,然後單獨的調用具體産品類的方法;而政策模式是由用戶端建立這些具體算法類,然後交由上下文來調用這些具體算法類中的方法。
政策類接口
public interface CodeLanguage {
void useLanguage();
}
具體政策類
public class CodeJava implements CodeLanguage {
@Override
public void useLanguage() {
System.out.println("使用Java語言程式設計");
}
}
public class CodePhp implements CodeLanguage {
@Override
public void useLanguage() {
System.out.println("使用Php語言程式設計");
}
}
這點和簡單工廠模式是抽象産品和具體産品代碼是一樣的,下面是不同點,實作一個上下文對象
public class CodeContext {
CodeLanguage codeLanguage;
public CodeContext1(CodeLanguage codeLanguage) {
this.codeLanguage = codeLanguage;
}
void useLanguage(){
codeLanguage.useLanguage();
}
}
使用模式
public class Application {
public static void main(String[] args) {
CodeContext context;
context = new CodeContext(new CodeJava());
context.useLanguage();
context = new CodeContext(new CodePhp());
context.useLanguage();
}
}
上面是一個最簡單的政策模式的實作方式,按照功能分為3個部分,定義政策抽象接口,然後根據具體算法實作政策接口,最後需要定義一個上下文對象。這裡的上下文對象主要用來切換算法,上下文對象裡面也是針對接口程式設計,具體算法實作被封裝了。
4.政策模式的了解
上面實作的隻是一種最簡單的政策模式的架構,實際應用的時候,我們可以針對不同情況修改上下文對象和具體的算法實作。比如說,可以增加一個抽象類實作作為算法模闆。抽象類裡面我們可以封裝一些公共的方法。這樣實作具體的算法的時候,每個算法公共部分就被分離出來。
政策模式的目的是把具體的算法抽離出來,把每個算法獨立出來。形成一系列有共同作用的算法組,然後這個算法組裡面的算法可以根據實際情況進行互相替換。
政策模式的中心不是如何實作這些算法,而是如何組織和調用這些算法。也就是把我們平時寫到一塊的算法解耦出來,獨立成一個子產品,增強程式的擴充性。
政策模式裡面的算法通常需要資料執行,我們可以根據實際情況把資料放在不同地方。例如可以放在上下文類裡面,然後每個算法都可以使用這些資料。或者對接口封裝一個抽象類,在抽象類裡面添加資料。這些可以根據實際的情況綜合考慮。設計模式裡面沒有一成不變的萬能模式,每種模式都有變化版本,需要根據實際的項目進行變通。
5.政策模式優缺點
政策模式的優點:
政策模式完全符合“開放-封閉原則”。
政策模式提供了管理相關算法族的辦法。恰當使用繼承可以把公共的代碼移到抽象政策類中,進而避免重複的代碼。
政策模式提供了一種可以替換繼承關系的辦法。如果不使用政策模式,那麼使用算法的環境類就可能會有一些子類,每一個子類提供一種不同的算法。但是,這樣一來算法的使用就和算法本身混在一起,不符合“單一職責原則”,而且使用繼承無法實作算法或行為在程式運作時的動态切換。
使用政策模式可以避免多重條件選擇語句。
更好的擴充性:在政策模式中擴充新的政策實作非常容易,隻要增加新的政策實作類,然後在選擇使用政策的地方選擇使用這個新的政策實作就好了。
政策模式缺點:
用戶端必須知道所有的政策類,并自行決定使用哪一個政策類,而且這樣也暴露了政策的具體實作。
由于政策模式把每個具體的政策實作都單獨封裝成為類,如果備選的政策很多的話,那麼對象的數目就會相應增多。
政策模式将造成系統産生很多具體政策類,任何細小的變化都将導緻系統要增加一個新的具體政策類。
政策模式的一系列算法地位是平等的,是可以互相替換的,事實上構成了一個扁平的算法結構,也就是在一個政策接口下,有多個平等的政策算法,就相當于兄弟算法。而且在運作時刻隻有一個算法被使用,這就限制了算法使用的層級,使用的時候不能嵌套使用。
6.模式優化
考慮到政策模式在使用的時候會過多的暴露政策類,代碼的耦合性過高,結合簡單工廠模式進行優化,對上下文類進行修改
public class CodeContext {
CodeLanguage codeLanguage;
public CodeContext(String type) {
switch (type){
case "java":
CodeJava codeJava=new CodeJava();
codeLanguage=codeJava;
break;
case "php":
CodePhp codePhp=new CodePhp();
codeLanguage=codePhp;
break;
}
}
void useLanguage(){
codeLanguage.useLanguage();
}
}
CodeContext context = new CodeContext("java");
context.useLanguage();
context = new CodeContext("php");
context.useLanguage();
相比傳統政策模式,我們把直接建立具體上下文對象改通過參數判斷來生成,這樣暴露給用戶端的隻有上下文對象,代碼的耦合度更低,可以說這既是簡單工廠模式的更新,也是政策模式的更新。
參考:
http://mobile.51cto.com/ahot-418972.htm http://blog.csdn.net/lmj623565791/article/details/24116745 http://blog.sina.com.cn/s/blog_7f311ef50102uxqz.html http://blog.csdn.net/yanbober/article/details/45498567