設計模式系列(一)——策略模式

概念:   

      策略模式做爲一種軟件設計模式,指對象有某個行爲,可是在不一樣的場景中,該行爲有不一樣的實現算法。(維基百科)java

理解概念:

      概念中說策略模式是某個行爲在不一樣場景下有不一樣的實現算法。咱們知道有一條設計原則是這樣的:分離變化的部分和不變的部分。在這個概念中咱們能夠知道。不變的地方,是這個行爲,變化的,是執行這個行爲所須要的算法,或者說是策略。算法

應用場景:

      這個模式的應用場景應該是這樣的。咱們須要對若干個均可以實現咱們所要的功能中選擇一個最合適的。舉一個簡單的例子:java君、Pascal君、Scala君三我的要去餐廳吃飯。但是呢,他們仨我的的口味不同,java君想吃麪向對象大餐,Pascal君想吃麪向過程大餐,而Scala君想吃函數式大餐,這時候假設你是餐廳服務員,你給每一個人點餐的時候,就要這樣寫了spring

if(pascal君) return 面向過程大餐;else 
if(java君)return 面向對象大餐;else
if(scala君)return 函數式大餐;

這就太糟了。由於若是又來了一個spring先生想要吃aop大餐,就要去更改源碼了。這不符合咱們「對修改關閉,對擴展開放」的原則。因此這種設計是不行的。編程

 

解決之道:

      咱們說要分離開變化的和不變的東西。變化的就是對不一樣的人要上不一樣的菜。咱們把這一點從代碼中分離出來。單獨封裝起來。利用多態,給每一類人一個點某種菜的能力。咱們可讓全部人實現一個Order接口,這個接口中定義了點菜這個方法,讓每一個人都去實現這個方法,而後在點菜的時候直接去調用每一個人的order方法。這樣若是在來新的人的話,咱們不用改動原有的代碼,只須要讓新人實現本身的order方法就能夠。這樣就符合設計原則了。下面是實現代碼。設計模式

/*
 * Created by 王鏡鑫 on 2016/10/7
 */
interface Order//點餐接口
{
    public void order();//點餐方法
}
class JAVA implements Order//java君實現點餐接口
{
    public void order()
    {
        System.out.println("I want a Object Oriented meal");
    }
}
class Pascal implements Order//Pascal君實現點餐接口
{
    public void order()
    {
        System.out.println("I want a Procedure Oriented meal");
    }
}
class Scala implements Order//Scala君實現點餐接口
{
    public void order()
    {
        System.out.println("I want a functional meal");
    }
}
public class Restaurant//餐廳
{
    private Order order = null;
    public void setOrder(Order order)//設置點餐的人。
    {
        this.order = order;
    }
    public void order()//讓點餐人點餐
    {
        order.order();
    }

    public static void main(String[] args)
    {
        Restaurant restaurant = new Restaurant();//實例化一個餐廳
        restaurant.setOrder(new JAVA());//將java君設置進去
        restaurant.order();//讓java君點餐
        restaurant.setOrder(new Pascal());//將Pascal君設置進去
        restaurant.order();//讓Pascal君點餐
        restaurant.setOrder(new Scala());//將Scala君設置進去
        restaurant.order();//讓Scala君點餐
    }
}

輸出以下:函數

I want a Object Oriented meal
I want a Procedure Oriented meal
I want a functional meal

可見,java君、Pascal君、Scala君都吃到了本身想吃的大餐。而且及時再來一個彙編先生,咱們也不怕,也不用修改原來的代碼。只須要在添加一個彙編先生類讓其實現點餐接口就能夠了。this

提煉總結:

      咱們經過一個例子。來描述了所謂的策略模式的應用場景,和如何應用策略模式解決問題,使代碼更易擴展,下降耦合。下面咱們總結一下策略模式。
      經過上面的例子,咱們得知,策略模式包含如下角色:spa

  •   Context:上下文類,起到承上啓下的封裝做用,屏蔽上層模塊對策略的直接訪問。
  •   Strategy:抽象策略類。一般是一個抽象(接口或者抽象類)定義每一個策略中的必須有的方法和屬性。
  •   ConcreteStrategy:具體策略類,是具體策略的實現。

三者的關係以下圖:scala

上下文中有一個策略屬性,還有一個設置策略的方法,一個工做方法。工做方法中實現的就是策略的工做方法。 具體的策略A和具體的策略B去實現了策略接口,實現了work方法。這樣在調用上下文的work方法,就是調用了實際設置的具體策略的work方法,從而實現了將執行策略與具體的策略解耦,有新的策略的時候,只須要再從新聲明一個策略類就能夠。
      策略模式是一種很是簡單的設計模式,策略模式是對不一樣的算法的封裝,把算法的責任和算法自己分離開來,將算法委派給不一樣的對象管理,用一句話來講,策略模式就是:實現一族算法,並將每個算法都封裝起來,使其相互交換。
      策略模式中,使用哪種策略是由用戶來決定的,這提升了系統的靈活性,可是這在必定程度上,也增長了客戶端的使用難度。由於客戶端須要瞭解不一樣的算法之間的區別,選擇合適的算法。策略模式還體現了這樣一個設計原則:針對接口編程,而不是針對實現編程。咱們在策略模式中,用一個接口表明行爲,根據多態,上下文在工做時執行的行爲,是這個接口的具體實現。思考咱們經常使用的jdk官方的排序方法。Colloctions.sort(List<T> list)和他的重載方法 sort(List<T> list, Comparator<? super T> c)他們的實現都是直接調用了List的sort方法,區別是一個傳入的比較器是null,一個是傳入了具體的比較器,比較器是null的那個方法,list中的元素T也是實現了Comparablel接口的。這就是一個典型的策略模式的應用。再排序的時候,因爲不一樣的須要排序的類的排序規則不同,也就是策略不同,因此咱們把策略封裝到客戶部分,也就是具體須要排序的類中,也就是讓具體須要排序的類實現Comparable接口,而後在傳入到排序的算法中的時候,排序的算法在比較兩個元素的前後順序的時候直接調用其compareTo方法,根據多態,他調用的實際上是具體傳入的compareTo方法。也就是封裝到子類中的具體的比較策略,這樣就能實現了具體的排序。這是策略模式在排序中的應用。
因爲知識水平有限,文章中有疏漏或者錯誤的地方,歡迎你們留言指正。設計

相關文章
相關標籤/搜索