1. 程式人生 > >【原創】從策略模式閑扯到lamda表達式

【原創】從策略模式閑扯到lamda表達式

可能 ... bubuko 收獲 方式 缺陷 表達式 return 分享

引言

策略模式,講這個模式的文章很多,但都缺乏一個循序漸進的過程。講lamda表達式的文章也很多,但基本都是堆砌一堆的概念,很少帶有自己的見解。博主一時興起,想寫一篇這二者的文章。需要說明的是,在看這篇文章的時候,請忘記所有的概念。容博主一步一步的帶你們入坑。

正文

假設我們有一個Hero類,其UML圖如下
技術分享圖片
這個時候,我們有一個需求:

  • 我們要找出type為刺客的Hero

這時,我們先封裝一個要根據type類型來篩選Hero的方法

public static List<Hero> getHero(List<Hero> heroList, String type){
        List<Hero> result = new ArrayList<Hero>();
        for(Hero hero : heroList){
            if(type.equals(hero.getType())){
                result.add(hero);
            }
        }
        return result;
    }

然後呢,做如下調用

getHero(heroList, "刺客");

突然有一天,產品突然改需求,現在的需求

  • 我們要找出stature(身高)大於170的Hero

也很簡單嘛,再加一個重載的getHero方法就可以嘛,重載的getHero(List heroList, int stature)方法如下

public static List<Hero> getHero(List<Hero> heroList, int stature){
        List<Hero> result = new ArrayList<Hero>();
        for(Hero hero : heroList){
            if(hero.getStature() > stature){
                result.add(hero);
            }
        }
        return result;
    }

然後呢,做如下調用

getHero(heroList, 170);

又過了幾日,產品喪心病況的又改需求,現在最新的需求

  • 要找出stature(身高)大於170並且type類型為刺客的Hero

當然,你或許說了,可以再加一個getHero(List heroList, String type, int stature)方法呀。不過呢,這種改法不夠優雅。方法體中存在大量相同的代碼,只是判斷條件稍作改變。在這種情況下使用策略模式,就能夠解決這個問題。
稍微介紹一下策略模式
策略模式
意圖:策略模式定義了一系列的算法,並將每一個算法封裝起來,而且使他們可以相互替換,讓算法獨立於使用它的客戶而獨立變化。

主要解決:在有多種算法相似的情況下,使用 if...else 所帶來的復雜和難以維護。

何時使用:一個系統有許多許多類,而區分它們的只是他們直接的行為。

如何解決:將這些算法封裝成一個一個的類,任意地替換。

ps:在這裏,上面的算法指的就是上面提到的判斷條件。我們將判斷條件封裝為相應的類。

此時代碼結構如下圖所示
技術分享圖片
那麽此時的getHero方法如下所示

public static List<Hero> getHero(List<Hero> heroList, Predicate<Hero> predicate){
        List<Hero> result = new ArrayList<Hero>();
        for(Hero hero : heroList){
            if(predicate.test(hero)){
                result.add(hero);
            }
        }
        return result;
    }

然後呢,根據需求做如下調用,想找那種類型的Hero,就傳那種類型的Predicate進去。

getHero(heroList,new TMPredicate());

可是呢,機智的你又發現了一個缺陷,每次新增一個算法,要新加一個實現類。於是,機智的你提出,利用匿名內部類來做調用,不寫實現類,於是調用代碼變成下面這樣

getHero(heroList,new Predicate<Hero>() {
    @Override
    public boolean test(Hero t) {
        return t.getStature() > 170 && "刺客".equals(t.getType());
    }
});

機智的你突然間又覺得:這麽寫,占用了太多的行數,看起來不夠美觀,於是,你決定用lamda表達式來改寫,於是代碼最終變成下面的樣子

getHero(heroList,(t)->t.getStature() > 170 && "刺客".equals(t.getType()));

好了,到這裏就結束了,是不是比我們最開始的版本簡潔了不少,代碼優雅了很多。lamda主要的目的就是提供一個更加簡潔的代碼結構,但是對於初學者,它可能反而增加閱讀的難度。

當然,lamda表達式除了能簡化代碼代碼意外,還能並行處理元素,充分利用多核CPU的性能,例如下面的代碼

import java.util.Arrays;
import java.util.List;

public class Demo7 {
    public static void main(String[] args) {
        List<String> values = Arrays.asList("1","2","3","4");
        print(values);
    }

    public static void print(List<String> values){
       values.parallelStream().forEach(System.out :: println);//System.out表示對象,println表示方法
    }
}

輸出如下

3
4
1
2

總結

本文以循序漸近的方式說明了,我們為什麽要用策略模式以及如何用lamda表達式改寫策略模式。希望大家有所收獲。

參考文獻

《JAVA8實戰》

【原創】從策略模式閑扯到lamda表達式