1. 程式人生 > >Android開發之設計模式-策略模式

Android開發之設計模式-策略模式

在策略模式(Strategy Pattern)

一個類的行為或其演算法可以在執行時更改。這種型別的設計模式屬於行為型模式。

在策略模式中,我們建立表示各種策略的物件和一個行為隨著策略物件改變而改變的 context 物件。策略物件改變 context 物件的執行演算法。

意圖:定義一系列的演算法,把它們一個個封裝起來, 並且使它們可相互替換。

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

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

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

關鍵程式碼:實現同一個介面。

應用例項: 1、諸葛亮的錦囊妙計,每一個錦囊就是一個策略。 2、旅行的出遊方式,選擇騎自行車、坐汽車,每一種旅行方式都是一個策略。 3、JAVA AWT 中的 LayoutManager。

優點: 1、演算法可以自由切換。 2、避免使用多重條件判斷。 3、擴充套件性良好。

缺點: 1、策略類會增多。 2、所有策略類都需要對外暴露。

使用場景: 1、如果在一個系統裡面有許多類,它們之間的區別僅在於它們的行為,那麼使用策略模式可以動態地讓一個物件在許多行為中選擇一種行為。 2、一個系統需要動態地在幾種演算法中選擇一種。 3、如果一個物件有很多的行為,如果不用恰當的模式,這些行為就只好使用多重的條件選擇語句來實現。

注意事項:如果一個系統的策略多於四個,就需要考慮使用混合模式,解決策略類膨脹的問題。

例項:

劉備要到江東娶老婆了,走之前諸葛亮給趙雲(伴郎)三個錦囊妙計,說是按天機拆開解決棘手問題, 嘿,還別說,真是解決了大問題,搞到最後是周瑜陪了夫人又折兵呀,那咱們先看看這個場景是什麼樣子 的。 先說這個場景中的要素:三個妙計,一個錦囊,一個趙雲,妙計是小亮同志給的,妙計是放置在錦囊 裡,俗稱就是錦囊妙計嘛,那趙雲就是一個幹活的人,從錦囊中取出妙計,執行,然後獲勝,用 JAVA 程式 怎麼表現這個呢?我們先看類圖:

 

1、定義策略介面

/**
 * 這是諸葛亮老人家給趙雲的三個錦囊妙計的介面
 * */
public interface Istrategy {
    //每個錦囊妙計都是一個可執行的演算法
    void operate();
}

2、三個實現類,有三個妙計嘛:

BackDoor.java

/**找喬國老幫忙,使孫權不能殺劉備*/
public class BackDoor implements Istrategy{
    @Override
    public void operate() {
        System.out.print("找喬國老幫忙,讓吳國太給孫權施加壓力");
    }
}

GiveGreenLight.java

/**求吳國太開個綠燈*/
public class GiveGreenLight implements Istrategy{
    @Override
    public void operate() {
        System.out.print("求吳國太開個綠燈,放行");
    }
}
BlockEnemy.java
/**孫夫人斷後,擋住追兵**/
public class BlockEnemy implements Istrategy{
    @Override
    public void operate() {
        System.out.print("孫夫人斷後,擋住追兵");
    }
}

3、三個妙計是有了,那需要有個地方放這些妙計呀,放錦囊呀:

/**計謀有了,那還要有錦囊*/
public class Context {
    //建構函式,你要使用那個妙計
    private Istrategy istrategy;
    public Context(Istrategy istrategy){
        this.istrategy = istrategy;
    }

    //使用計謀了,看我出招了
    public void operate(){
        this.istrategy.operate();
    }
}

4、然後就是趙雲雄赳赳的揣著三個錦囊,拉著已步入老年行列的、還想著娶純情少女的、色迷迷的劉老 爺子去入贅了,嗨,還別說,小亮的三個妙計還真是不錯,瞅瞅:

​
public class ZhaoYun {
    /**
     * 趙雲出場了,他根據諸葛亮給他的交代,依次拆開妙計
     */
    public static void main(String [] args){
        Context context;

        //剛剛到吳國的時候拆第一個
        System.out.print("------------剛剛到吳國的時候拆第一個-----------");
        context = new Context(new BackDoor());//拿到妙計
        context.operate();//拆開執行
        System.out.print("\n\n\n\n\n\n\n\n\n");

        //劉備樂不思蜀了,拆第二個了
        System.out.print("------------劉備樂不思蜀了,拆第二個了-----------");
        context = new Context(new GiveGreenLight());
        context.operate();//執行了第二個錦囊了
        System.out.println("\n\n\n\n\n\n\n\n");

        //孫權的小兵追了,咋辦?拆第三個
        System.out.println("-----------孫權的小兵追了,咋辦?拆第三個-------");
        context = new Context(new BlockEnemy());
        context.operate();//孫夫人退兵
        /**
         *問題來了:趙雲實際不知道是那個策略呀,他只知道拆第一個錦囊,
         *而不知道是BackDoor這個妙計,咋辦? 似乎這個策略模式已經把計謀名稱寫出來了
         *
         * 錯!BackDoor、GivenGreenLight、BlockEnemy只是一個程式碼,你寫成first、second、
        third,沒人會說你錯!
         *
         * 策略模式的好處就是:體現了高內聚低耦合的特性呀,缺點嘛,1、策略類會增多。 2、所有策略類都需要對外暴露。
         */
    }
}

​

5、執行程式,輸出結果

就這三招,搞的周郎是“陪了夫人又折兵”呀!這就是策略模式,高內聚低耦合的特點也表現出來了, 還有一個就是擴充套件性,也就是 OCP 原則,策略類可以繼續增加下去,只要修改 Context.java 就可以了。

例項2:

假設我們要出去旅遊,而去旅遊出行的方式有很多,有步行,有坐火車,有坐飛機等等。而如果不使用任何模式,我們的程式碼可能就是這樣子的。

public class TravelStrategy {
	enum Strategy{
		WALK,PLANE,SUBWAY
	}
	private Strategy strategy;
	public TravelStrategy(Strategy strategy){
		this.strategy=strategy;
	}
	
	public void travel(){
		if(strategy==Strategy.WALK){
			print("walk");
		}else if(strategy==Strategy.PLANE){
			print("plane");
		}else if(strategy==Strategy.SUBWAY){
			print("subway");
		}
	}
	
	public void print(String str){
		System.out.println("出行旅遊的方式為:"+str);
	}
	
	public static void main(String[] args) {
		TravelStrategy walk=new TravelStrategy(Strategy.WALK);
		walk.travel();
		
		TravelStrategy plane=new TravelStrategy(Strategy.PLANE);
		plane.travel();
		
		TravelStrategy subway=new TravelStrategy(Strategy.SUBWAY);
		subway.travel();
	}
}

這樣做有一個致命的缺點,一旦出行的方式要增加,我們就不得不增加新的else if語句,而這違反了面向物件的原則之一,對修改封閉。而這時候,策略模式則可以完美的解決這一切。

1、需要定義一個策略介面。

public interface Strategy {
    void travel();
}

2、然後根據不同的出行方式實行對應的介面

public class WalkStrategy implements Strategy{

	@Override
	public void travel() {
		System.out.println("walk");
	}

}

 

public class PlaneStrategy implements Strategy{

	@Override
	public void travel() {
		System.out.println("plane");
	}

}

 

public class SubwayStrategy implements Strategy{

	@Override
	public void travel() {
		System.out.println("subway");
	}

}

3、 此外還需要一個包裝策略的類,並呼叫策略介面中的方法

public class TravelContext {
	Strategy strategy;

	public Strategy getStrategy() {
		return strategy;
	}

	public void setStrategy(Strategy strategy) {
		this.strategy = strategy;
	}

	public void travel() {
		if (strategy != null) {
			strategy.travel();
		}
	}
}

 4、測試一下程式碼

public class Main {
	public static void main(String[] args) {
		TravelContext travelContext=new TravelContext();
		travelContext.setStrategy(new PlaneStrategy());
		travelContext.travel();
		travelContext.setStrategy(new WalkStrategy());
		travelContext.travel();
		travelContext.setStrategy(new SubwayStrategy());
		travelContext.travel();
	}
}

5、執行程式,輸出結果

 

可以看到,應用了策略模式後,如果我們想增加新的出行方式,完全不必要修改現有的類,我們只需要實現策略介面即可,這就是面向物件中的對擴充套件開放準則。假設現在我們增加了一種自行車出行的方式。只需新增一個類即可。

public class BikeStrategy implements Strategy{

	@Override
	public void travel() {
		System.out.println("bike");
	}

}

之後設定策略即可

public class Main {
	public static void main(String[] args) {
		TravelContext travelContext=new TravelContext();
		travelContext.setStrategy(new BikeStrategy());
		travelContext.travel();
	}
}

策略模式詳解連結:

https://wenku.baidu.com/view/57f37f4fc850ad02de804152.html?st=1

下篇觀察者模式,待續...