第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

工廠模式

工廠模式是平時(shí)開發(fā)過程中最常見的設(shè)計(jì)模式。工廠模式解決類的實(shí)例化問題,它屬于創(chuàng)建型模式。工廠模式也經(jīng)常會(huì)和其他設(shè)計(jì)模式組合使用。

試想你去麥當(dāng)勞買一個(gè)漢堡。你只需要告訴收銀員要一個(gè)xx漢堡。過一會(huì)就會(huì)有一個(gè)此類型的漢堡被制作出來。而你完全不需要知道這個(gè)漢堡是怎么被制作出來的。這個(gè)例子中你就是客戶端代碼,麥當(dāng)勞就是工廠,負(fù)責(zé)生產(chǎn)漢堡。漢堡是接口,而具體的某一種漢堡,比如說香辣雞腿堡,就是實(shí)現(xiàn)了漢堡接口的類。

我們繼續(xù)通過另外一個(gè)例子,深入理解工廠模式?,F(xiàn)在我們給某款音樂軟件開發(fā)一個(gè)推薦功能。需求是能夠根據(jù)用戶選擇的音樂風(fēng)格,推薦不同風(fēng)格的歌曲清單。那么你打算怎么實(shí)現(xiàn)呢?

1. 音樂推薦器1.0版本

如果之前沒有學(xué)習(xí)過設(shè)計(jì)模式,很可能你的實(shí)現(xiàn)會(huì)是這樣。編寫 RecommendMusicService 類,里面有一個(gè) Recommend方法。根據(jù)輸入的風(fēng)格不同,執(zhí)行不同的推薦邏輯。代碼如下:

public class RecommendMusicService {
    public List<String> recommend(String style) {
        List<String> recommendMusicList = new ArrayList<>();

        if ("metal".equals(style)) {
            recommendMusicList.add("Don't cry");
        } else if ("country".equals(style)) {
            recommendMusicList.add("Hotel california");
        } else if ("grunge".equals(style)) {
            recommendMusicList.add("About a girl");
        }else {
            recommendMusicList.add("My heart will go on");
        }

        return recommendMusicList;
    }
}

是不是覺得 recommed 方法太長了? OK,我們重構(gòu)下,把每種音樂風(fēng)格的推薦邏輯封裝到相應(yīng)的方法中。這樣推薦方法就可以復(fù)用了。

public class RecommendMusicService {
    public List<String> recommend(String style) {
        List<String> recommendMusicList = new ArrayList<>();

        if ("metal".equals(style)) {
            recommendMetal(recommendMusicList);
        } else if ("country".equals(style)) {
            recommendCountry(recommendMusicList);
        } else if ("grunge".equals(style)) {
            recommendGrunge(recommendMusicList);
        }else {
            recommendPop(recommendMusicList);
        }

        return recommendMusicList;
    }

    private void recommendPop(List<String> recommendMusicList) {
        recommendMusicList.add("My heart will go on");
        recommendMusicList.add("Beat it");
    }

    private void recommendGrunge(List<String> recommendMusicList) {
        recommendMusicList.add("About a girl");
        recommendMusicList.add("Smells like teen spirit");
    }

    private void recommendCountry(List<String> recommendMusicList) {
        recommendMusicList.add("Hotel california");
        recommendMusicList.add("Take Me Home Country Roads");
    }

    private void recommendMetal(List<String> recommendMusicList) {
        recommendMusicList.add("Don't cry");
        recommendMusicList.add("Fade to black");
    }
}

這樣是不是很完美了!recommend 方法精簡了很多,而且每種不同的推薦邏輯都被封裝到相應(yīng)的方法中了。那么,如果再加一種風(fēng)格推薦怎么辦?這有什么難,recommed 方法中加分支就好啦。然后在 RecommendMusicService 中增加一個(gè)對應(yīng)的推薦方法。
等等,是不是哪里不太對?回想一下設(shè)計(jì)模式6大原則的開閉原則----對擴(kuò)展開放,對修改關(guān)閉。面對新風(fēng)格推薦的需求,我們一直都在修改 RecommendMusicService 這個(gè)類。以后每次有新風(fēng)格推薦要添加,都會(huì)導(dǎo)致修改 RecommendMusicService 。顯然這是個(gè)壞味道。

那么如何做到實(shí)現(xiàn)新的風(fēng)格推薦需求時(shí),滿足開閉原則呢?

2. 音樂推薦器2.0版本

添加新需求時(shí),如何做到不修改,去擴(kuò)展?是不是想到了單一職責(zé)?是的,類的職責(zé)越單一,那么它就越穩(wěn)定。RecommendMusicService 類的職責(zé)太多了,負(fù)責(zé)n種風(fēng)格的推薦。OK,那么我們第一件事就是要減少 RecommendMusicService 類的職責(zé),把每種不同風(fēng)格的推薦提取到不同的類當(dāng)中。
比如MetalMusicRecommendServicePopMusicRecommendService、CountryMusicRecommendService。這些類都可以通過 recommed 方法生成推薦的歌曲清單。而 RecommendMusicService 類只是通過調(diào)用不同 MusicRecommendService 的 recommed 方法來實(shí)現(xiàn)推薦。代碼如下:

MetalMusicRecommendService 類:

public class MetalMusicRecommendService {
    public List<String> recommend(){
        List<String> recommendMusicList = new ArrayList<>();

        recommendMusicList.add("Don't cry");
        recommendMusicList.add("Fade to black");

        return recommendMusicList;
    }
}

同類型的還有 GrungeMusicRecommendService、PopMusicRecommendServiceCountryMusicRecommendService

現(xiàn)在我們來改造 MusicRecommendService 類:

public class RecommendMusicService {

    private MetalMusicRecommendService metalMusicRecommendService = new MetalMusicRecommendService();
    private GrungeMusicRecommendService grungeMusicRecommendService = new GrungeMusicRecommendService();
    private CountryMusicRecommendService countryMusicRecommendService = new CountryMusicRecommendService();
    private PopMusicRecommendService popMusicRecommendService = new PopMusicRecommendService();

    public List<String> recommend(String style) {
        List<String> recommendMusicList = new ArrayList<>();

        if ("metal".equals(style)) {
            metalMusicRecommendService.recommend();
        } else if ("country".equals(style)) {
            countryMusicRecommendService.recommend();
        } else if ("grunge".equals(style)) {
            grungeMusicRecommendService.recommend();
        }else {
            popMusicRecommendService.recommend();
        }

        return recommendMusicList;
    }

}

改造后,如果有了新音樂風(fēng)格推薦的需求,只需要增加相應(yīng)的 xxxMusicRecommendService 類。然后在 RecommendMusicService 中增加相應(yīng)分支即可。這樣就做到了開閉原則。那么還有什么違背設(shè)計(jì)原則的地方嗎?RecommendMusicService 是不是依賴的 xxMusicRecommendService 類太多了?

沒錯(cuò),而且這么多類,實(shí)際上都是做推薦的事情,且都是通過 recommend 方法提供推薦結(jié)果。這完全可以抽象出接口,比如 MusicRecommendInterface。那么 RecommendMusicService 依賴 MusicRecommendInterface 就可以了。這解決了依賴反轉(zhuǎn)問題----應(yīng)該依賴接口,而不是依賴具體實(shí)現(xiàn)。

我們又復(fù)習(xí)了單一職責(zé)和依賴反轉(zhuǎn)原則。不愧是指導(dǎo)設(shè)計(jì)模式的原則,真的是無處不在。依賴 MusicRecommendInterface 沒問題,但是不同的音樂風(fēng)格,怎么能實(shí)例化 MusicRecommendInterface 的某個(gè)具體實(shí)現(xiàn)呢?工廠模式于是就應(yīng)運(yùn)而生了!

3. 音樂推薦器3.0版本

我們回顧一下文章開頭說到,工廠模式解決的是類的實(shí)例化。無論你需要哪種風(fēng)格的 MusicRecommendService,只需要告訴工廠,工廠會(huì)給你實(shí)例化好你需要的具體實(shí)現(xiàn)。而工廠能做到這些是基于繼承和多態(tài)。
RecommendMusicService 只需要依賴 MusicRecommendInterface,具體需要哪個(gè)MusicRecommendService 的實(shí)現(xiàn),只需要告訴 RecommendServiceFactory 即可。MusicRecommendService 拿到具體的實(shí)現(xiàn)后調(diào)用它的 recommand 方法,就可以得到相應(yīng)風(fēng)格的推薦歌曲清單。

首先我們需要定義所有 MusicRecommendService 要實(shí)現(xiàn)的接口,很簡單,只有一個(gè) recommend 方法:

public interface MusicRecommendInterface {
    List<String> recommend();
}

我們2.0版本中的 xxxMusicRecommendService 都需要實(shí)現(xiàn)此接口,例如:

public class GrungeMusicRecommendService implements MusicRecommendInterface {
    public List<String> recommend() {
        List<String> recommendMusicList = new ArrayList<>();

        recommendMusicList.add("About a girl");
        recommendMusicList.add("Smells like teen spirit");

        return recommendMusicList;
    }
}

不同音樂風(fēng)格的推薦邏輯在各自實(shí)現(xiàn)的 recommend() 方法中。
下面就是工廠模式中的工廠代碼了,其實(shí)很簡單,只是根據(jù)不同的參數(shù)實(shí)例化不同的實(shí)現(xiàn)并返回。

public class MusicRecommendServiceFactory {
    MusicRecommendInterface createMusicRecommend(String style) {
        if ("metal".equals(style)) {
            return new MetalMusicRecommendService();
        } else if ("country".equals(style)) {
            return new CountryMusicRecommendService();
        } else if ("grunge".equals(style)) {
            return new GrungeMusicRecommendService();
        } else {
            return new PopMusicRecommendService();
        }
    }
}

我們再來看看 RecommendMusicService 的代碼:

public class RecommendMusicService {

    private MusicRecommendServiceFactory recommendMusicServiceFactory = new MusicRecommendServiceFactory();

    public List<String> recommend(String style) {

        MusicRecommendInterface musicRecommend = recommendMusicServiceFactory.createMusicRecommend(style);

        return musicRecommend.recommend();
    }
}

是不是簡單多了,已經(jīng)不再依賴那么多的 MusicRecommendInterface 的實(shí)現(xiàn)了。它要做的事情僅僅是通過工廠得到想要的 RecommendMusicService 實(shí)現(xiàn),然后調(diào)用它的 recommend() 方法,就可以得到你想要的推薦結(jié)果。
類圖如下:
圖片描述
以上三種實(shí)現(xiàn)方式總結(jié)如下:
圖片描述

4. 小結(jié)

本節(jié)我們通過音樂推薦器的例子,實(shí)踐了如何找到程序中違反設(shè)計(jì)原則的地方,并通過工廠模式來解決這些問題。使用設(shè)計(jì)模式可以讓程序更符合程序設(shè)計(jì)原則,從而寫出更為健壯的代碼。我們應(yīng)牢記工廠模式解決的是類的實(shí)例化問題。這個(gè)例子很簡單,不過涉及到的知識(shí)點(diǎn)卻很多。有封裝、多態(tài)、單一職責(zé)和依賴反轉(zhuǎn)等??梢娨氚殉绦蛟O(shè)計(jì)好,必須熟練掌握這些基本概念和原則。