最近中文字幕高清中文字幕无,亚洲欧美高清一区二区三区,一本色道无码道dvd在线观看 ,一个人看的www免费高清中文字幕

策略模式

大家一定都使用過(guò)電子地圖。在地圖中輸入出發(fā)地和目的地,然后再選取你的出行方式,就可以計(jì)算出最優(yōu)線路以及預(yù)估的時(shí)長(zhǎng)。出行方式有駕車、公交、步行、騎行等。出行方式不同,計(jì)算的線路和時(shí)間當(dāng)然也不同。
其實(shí)出行方式換個(gè)詞就是出行策略。而策略模式就是針對(duì)此類問(wèn)題的設(shè)計(jì)模式。生活中這種例子太多了,比如購(gòu)物促銷打折的策略、計(jì)算稅費(fèi)的策略等等。相應(yīng)的策略模式也是一種常用的設(shè)計(jì)模式。本節(jié)我們會(huì)以電子地圖為例,比較工廠模式和策略模式,講解策略模式的原理。最后結(jié)合工廠模式改造策略模式的代碼實(shí)現(xiàn),以達(dá)到更高的設(shè)計(jì)目標(biāo)。

1. 實(shí)現(xiàn)策略模式

接下來(lái)我們就以電子地圖為例,講解如何用策略模式實(shí)現(xiàn)。不過(guò)先別著急,上一節(jié)我們學(xué)習(xí)了工廠模式,看起來(lái)電子地圖也可以用工廠模式來(lái)實(shí)現(xiàn)。所以我們先來(lái)看看用工廠模式如何實(shí)現(xiàn)。下面的例子為了方便展示,接口入?yún)⒅挥谐鲂蟹绞剑÷粤顺霭l(fā)地和目的地。計(jì)算結(jié)果是預(yù)估時(shí)長(zhǎng)。

1.1 工廠模式實(shí)現(xiàn)電子地圖

首先我們需要一個(gè)策略接口,不同策略實(shí)現(xiàn)該接口。再搭配一個(gè)策略工廠。客戶端代碼只需要根據(jù)用戶的出行方式,讓工廠返回具體實(shí)現(xiàn)即可,由具體的實(shí)現(xiàn)來(lái)提供算法計(jì)算。以工廠模式實(shí)現(xiàn)的電子地圖代碼如下。
TravelStrategy接口代碼:

public interface TravelStrategy {
    int calculateMinCost();
}

TravelStrategy接口的實(shí)現(xiàn)代碼:

public class SelfDrivingStrategy implements TravelStrategy {
    @Override
    public int calculateMinCost() {
        return 30;
    }
}

TravelStrategyFactory代碼:

public class TravelStrategyFactory {
    public TravelStrategy createTravelStrategy(String travelWay) {
        if ("selfDriving".equals(travelWay)) {
            return new SelfDrivingStrategy();
        } if ("bicycle".equals(travelWay)) {
            return new BicycleStrategy();
        } else {
            return new PublicTransportStrategy();
        }
    }
}

TravelService對(duì)外提供計(jì)算方法,通過(guò)工廠生成所需要的 strategy。代碼如下:

public class TravelService {
    private TravelStrategyFactory travelStrategyFactory = new TravelStrategyFactory();

    public int calculateMinCost(String travelWay) {
        TravelStrategy travelStrategy = travelStrategyFactory.createTravelStrategy(travelWay);
        return travelStrategy.calculateMinCost();
    }
}

代碼結(jié)構(gòu)和我們上一節(jié)講解的音樂(lè)推薦器幾乎一模一樣??此埔埠芎玫亟鉀Q了我們的設(shè)計(jì)問(wèn)題。接下來(lái)我們看看如何用策略模式解決這個(gè)問(wèn)題,然后我們?cè)賹?duì)兩種模式做對(duì)比。

1.2 策略模式實(shí)現(xiàn)電子地圖

使用策略模式,需要增加一個(gè)策略上下文類(Context)。Context類持有策略實(shí)現(xiàn)的引用,并且對(duì)外提供計(jì)算方法。Context類根據(jù)持有策略的不同,實(shí)現(xiàn)不同的計(jì)算邏輯??蛻舳舜a只需要調(diào)用 Context 類的計(jì)算方法即可。如果想切換策略實(shí)現(xiàn),那么只需要改變Context類持有的策略實(shí)現(xiàn)即可。
TravelStrategy 接口和實(shí)現(xiàn)的代碼不變,請(qǐng)參照上面工廠模式中給出的代碼。其他代碼如下:
StrategyContext 類:

public class StrategyContext {
    private TravelStrategy strategy;

    public StrategyContext(TravelStrategy strategy) {
        this.strategy = strategy;
    }

    public int calculateMinCost(){
        return strategy.calculateMinCost();
    }

StrategyContext 持有某種 TravelStrategy 的實(shí)現(xiàn),它對(duì)外提供的calculateMinCost 方法,實(shí)際是對(duì) TravelStrategy 做了一層代理。想切換不同算法的時(shí)候,只需更改 StrategyContext 持有的 TravelStrategy 實(shí)現(xiàn)。

TravelService 對(duì)外提供計(jì)算方法,代碼如下:

public class TravelService {
    private StrategyContext strategyContext;

    public int calculateMinCost(String travelWay){

        if ("selfDriving".equals(travelWay)) {
            strategyContext = new StrategyContext(new SelfDrivingStrategy());
        } if ("bicycle".equals(travelWay)) {
            strategyContext = new StrategyContext(new BicycleStrategy());
        } else {
            strategyContext = new StrategyContext(new PublicTransportStrategy());
        }

        return strategyContext.calculateMinCost();
    }
}

可以看到 TravelService 中只會(huì)和 Context 打交道,初始化 Context 時(shí),根據(jù)不同的出行方式,設(shè)置不同的策略??吹竭@里你是不是會(huì)有疑問(wèn),使用工廠模式消除了客戶端代碼的條件語(yǔ)句。怎么使用策略模式,條件語(yǔ)句又回來(lái)了?別急,我們繼續(xù)向下看。

最后我們看一下策略模式的類圖:
圖片描述

2. 策略模式優(yōu)缺點(diǎn)

2.1 優(yōu)點(diǎn)

  1. 使用策略模式,可以根據(jù)策略接口,定義一系列可供復(fù)用的算法或者行為;
  2. 調(diào)用方只需要持有Context的引用即可。而無(wú)需知道具體的策略實(shí)現(xiàn)。滿足迪米特法則;
  3. Context 在策略的方法之外可以做一些通用的切面邏輯。

GOF的《設(shè)計(jì)模式》著作中認(rèn)為策略模式可以消除一些條件語(yǔ)句,我對(duì)此持懷疑態(tài)度。正如上面的例子,雖然由于Context在初始化的時(shí)候已經(jīng)指定了策略實(shí)現(xiàn),在計(jì)算邏輯中不需要根據(jù)條件選擇邏輯分支。但是,客戶端代碼在初始化Context的時(shí)候,如何判斷應(yīng)該傳入哪個(gè)策略實(shí)現(xiàn)呢?其實(shí)在客戶端代碼或者別的地方還是缺少不了條件判斷。所以這里消除條件語(yǔ)句,只是針對(duì)算法邏輯的條件判斷。

第一個(gè)優(yōu)點(diǎn)是策略模式解決的核心問(wèn)題。但其實(shí)工廠模式也是可以做到的。第二點(diǎn),我認(rèn)為很重要,客戶端代碼只需要和 Context 打交道即可,避免了和不同策略類、工廠類的接觸。工廠模式中,客戶端代碼需要知道工廠類和產(chǎn)品類,兩個(gè)類。正好復(fù)習(xí)一下迪米特法則,如果兩個(gè)類沒(méi)有必要直接通信,那么兩個(gè)類就沒(méi)有必要相互作用??梢酝ㄟ^(guò)第三方來(lái)間接調(diào)用。

2.2 缺點(diǎn)

  1. 客戶端代碼需要知道不同的策略以及如何選擇策略。因此可以看到上面的客戶端代碼有著丑陋的條件判斷;
  2. 由于策略類實(shí)現(xiàn)同樣的接口,所以參數(shù)列表要保持一致,但可能并不是所有的策略都需要全部參數(shù)。

3. 策略模式與工廠模式結(jié)合使用

針對(duì)第一個(gè)缺點(diǎn)。我們可以通過(guò)策略模式與工廠模式結(jié)合使用來(lái)改進(jìn)。通過(guò)進(jìn)一步封裝,消除客戶端代碼的條件選擇。

我們修改一下StrategyContext類,代碼如下:

public class StrategyContext {
    private TravelStrategy strategy;

    public StrategyContext(String travelWay) {
        if ("selfDriving".equals(travelWay)) {
            strategy = new SelfDrivingStrategy();
        } if ("bicycle".equals(travelWay)) {
            strategy = new BicycleStrategy();
        } else {
            strategy = new PublicTransportStrategy();
        }
    }

    public int calculateMinCost(){
        return strategy.calculateMinCost();
    }
}

可以看到我們初始化的邏輯和工廠的邏輯很相似。這樣條件判斷就提煉到 Context 類中了。而客戶端代碼將會(huì)簡(jiǎn)潔很多,只需要在初始化 StrategyContext 時(shí),傳入相應(yīng)的出行方式即可。代碼如下:

public class TravelService {
    private StrategyContext strategyContext;

    public int calculateMinCost(String travelWay){

        strategyContext = new StrategyContext(travelWay);

        return strategyContext.calculateMinCost();
    }
}

改進(jìn)后,客戶端代碼現(xiàn)在已經(jīng)完全不知道策略對(duì)象的存在了。條件判斷也被消除了。其實(shí)很多時(shí)候我們都是通過(guò)搭配不同設(shè)計(jì)模式來(lái)達(dá)到我們的設(shè)計(jì)目標(biāo)的。

策略+工廠模式類圖如下:
圖片描述

4. 策略模式適用場(chǎng)景

當(dāng)存在多種邏輯不同,但屬于同一類型的行為或者算法時(shí),可以考慮使用策略模式。以此來(lái)消除你算法代碼中的條件判斷。同時(shí)讓你的代碼滿足多種設(shè)計(jì)原則。

很多時(shí)候,工廠模式和策略模式都可以為你解決同類問(wèn)題。但你要想清楚,你想要的是一個(gè)對(duì)象,還是僅僅想要一個(gè)計(jì)算結(jié)果。如果你需要的是一個(gè)對(duì)象,并且想用它做很多事情。那么請(qǐng)使用工廠模式。而你僅僅想要一個(gè)特定算法的計(jì)算結(jié)果,那么請(qǐng)使用策略模式。

策略模式屬于對(duì)象行為模式,而工廠屬于創(chuàng)建型模式。策略模式和工廠模式對(duì)比如下:
圖片描述

5. 小結(jié)

策略模式解決的問(wèn)題是如何封裝可供復(fù)用的算法或者行為。策略模式滿足了單一職責(zé)、開(kāi)閉、迪米特法則、依賴倒轉(zhuǎn)等原則。我們一定想清楚策略模式的適用場(chǎng)景,否則某些時(shí)候你會(huì)搞不清到底用工廠模式還是策略模式。最后提醒大家,設(shè)計(jì)模式很多時(shí)候都是混合使用,我們不應(yīng)該局限于使用某一種設(shè)計(jì)模式來(lái)解決問(wèn)題。