設計模式:策略模式,Java集合定製排序的核心思想

前言

前陣子面試的時候,有個面試官問我瞭解哪些設計模式嗎?我說了策略模式。接着他問有哪些場景應用,我又回答他jdk的集合工具類有個排序方法就用到了策略模式,也就是java.util包下的Collections類,該類中有個sort方法,咱們能夠自定義排序規則實現集合的定製排序,這就是策略模式最直接的應用,說完以後他點點頭,料想對個人回答仍是比較滿意吧,固然我也只是在這道面試題上裝裝逼而已,畢竟最後面試結束時他說了句請回去等消息吧。。。。java

什麼是策略模式

言歸正傳,今天咱們學習設計模式系列的策略模式,先了解下其定義。面試

策略模式,也叫政策模式,其思想是:定義一組算法,將每一個算法都封裝起來,而且使它們之間能夠互換。它的最大特色是使得算法能夠在不影響客戶端的狀況下發生變化,從而改變不一樣的功能。就拿上面說的 sort 方法舉例,該方法中接收一個Comparator接口的參數,對sort 方法來講,它並不關心Comparator接口的具體實現,只要咱們傳入的參數是該接口類型的就好,這樣一來,咱們就能夠本身去實現Comparator接口,在其實現類裏定義咱們想要的排序規則,好比對集合的某個字段作升序仍是降序排列,這正是策略模式的直接應用。算法

寫段代碼簡單表示一下:設計模式

public static void main(String[] args) {
   
    List<Integer> list1 = new ArrayList<>();
    list1.add(1);
    list1.add(20);
    list1.add(3);
    
    Collections.sort(list1, new Comparator<Integer>() {
        @Override
        public int compare(Integer o1, Integer o2) {
            return o1 - o2;
        }
    });

    System.out.println("升序=======" + list1.toString());

    Collections.sort(list1, new Comparator<Integer>() {
        @Override
        public int compare(Integer o1, Integer o2) {
            return o2 - o1;
        }
    });

    System.out.println("降序=======" + list1.toString());
}

組成

瞭解了策略模式的定義和例子後,咱們看下策略模式的組成角色。ide

策略模式包含三個角色:函數

  • Strategy抽象策略角色 :策略、算法家族的抽象,一般爲接口,定義每一個策略或算法必須具備的方法和屬性。用上面的集合排序舉例,該角色就對應着Comparator接口。
  • ConcreteStrategy具體策略角色 :實現抽象策略中的操做,該類含有具體的算法。也就是咱們自定義的Comparator實現類。
  • Context封裝角色 :它也叫作上下文角色,內部會持有一個抽象角色的引用,給客戶端調用。該角色就對應着Collections工具類自己,該類中持有對Comparator接口的引用,能夠接收咱們自定義的具體的實現類。

經過這三個角色,咱們能夠簡單列出策略模式的類圖:工具

看的出來,策略模式的類圖仍是比較簡單的,根據這張類圖,咱們寫一下它的代碼實現吧。學習

通用類代碼

抽象策略角色:this

public interface Strategy {
    //策略模式的算法規則
    public void doSomething();
}

具體的策略角色:設計

public class ConcreteStrategy1 implements Strategy {
    public void doSomething() {
        System.out.println("具體策略1的運算法則");
    }
}

public class ConcreteStrategy2 implements Strategy {
    public void doSomething() {
        System.out.println("具體策略2的運算法則");
    }
}

封裝角色:

public class Context {
    //抽象策略
    private Strategy strategy = null;

    //構造函數設置具體策略 
    public Context(Strategy _strategy) {
        this.strategy = _strategy;
    }

    //封裝後的策略方法 
    public void doAnythinig() {
        this.strategy.doSomething();
    }
}

建好三個角色後,當客戶端要調用時,先肯定要使用哪一種具體的策略,建立出對應的策略角色對象,再傳進封裝角色就能夠了,具體代碼以下:

public class Client {
    public static void main(String[] args) {
        //聲明一個具體的策略 
        Strategy strategy = new ConcreteStrategy1();
        //聲明上下文對象 
        Context context = new Context(strategy);
        //執行封裝後的方法 
        context.doAnythinig();
    }
}

總結

策略模式的介紹就講到這裏了,提及來,策略模式算是比較簡單的設計模式了,但它在實際項目中也用的比較多,舉個例子,我以前所在公司中有個項目就用到了策略模式。

那個項目屬於電商類的系統,每類商品都有本身的優惠券,下單結算金額時須要計算商品和優惠券的價格總和,這裏有個比較頭疼的問題,由於每種類型的商品都有獨特的優惠券,若是用傳統的 if/else 判斷商品和優惠券的種類的話,那麼添加一種商品或優惠券都會使得下單的結算邏輯都須要從新修改,這很明顯不符合開閉原則。針對這種狀況,咱們採用了策略模式的思想,對代碼作了以下改造,

一、定義一個擁有商品和優惠券屬性的抽象策略角色

二、同時針對每種類型的商品建立對應的具體策略角色,定義本身獨特的計算優惠券策略

三、在下單結算的方法中,根據商品和優惠券類型建立對應的具體策略對象,把該對象傳入一個封裝角色後並調用結算金額的方法

這樣一來就能夠根據不一樣商品和優惠券種類計算出對應的金額了,並且代碼的封裝變得更加的抽象,商品具體的策略之間互相獨立,不會牽一髮而動全身,省心又省力。

以上就是策略模式的一個具體應用,固然,策略模式的應用還有不少,我也就簡單介紹其中的一個使用場景,經過實際例子讓你們感覺下設計模式的魅力,畢竟養兵千日,用兵一時,咱們學再多的理論知識不就是爲了有一天能用到實際嗎?

相關文章
相關標籤/搜索