程序員必知的23種設計模式之策略模式

1. 模式引入–鴨子項目

具體要求如下:

  1. 有各種鴨子(比如 野鴨、北京鴨、水鴨等, 鴨子有各種行爲,比如 叫、飛行等)

  2. 顯示鴨子的信息

2. 傳統方案解決鴨子問題

定義一個抽象類,其中實現了叫和飛的功能,顯示的方法設置爲抽象,交給子類實現

在這裏插入圖片描述

3. 傳統方式解決鴨子問題分析和解決方案

  1. 其它鴨子,都繼承了Duck類,所以fly讓所有子類都會飛了,這是不正確的

  2. 上面說的1 的問題,其實是繼承帶來的問題:對類的局部改動,尤其超類的局部改動,會影響其他部分。會有溢出效應

  3. 爲了改進1問題,我們可以通過覆蓋fly 方法來解決 => 覆蓋解決

  4. 問題又來了,如果我們有一個玩具鴨子ToyDuck, 這樣就需要ToyDuck去覆蓋Duck的所有實現的方法 => 解決思路 策略模式 (strategy pattern)

4. 策略模式基本介紹

  1. 策略模式(Strategy Pattern)中,定義算法族,分別封裝起來,讓他們之間可以互相替換,此模式讓算法的變化獨立於使用算法的客戶

  2. 這算法體現了幾個設計原則,第一、把變化的代碼從不變的代碼中分離出來;第二、針對接口編程而不是具體類(定義了策略接口);第三、多用組合/聚合,少用繼承(客戶通過組合方式使用策略)。

4.1 策略模式的原理類圖

在這裏插入圖片描述

4.2 說明

客戶context 有成員變量strategy或者其他的策略接口,至於需要使用到哪個策略,我們可以在構造器中指定.

5. 策略模式解決鴨子問題

UML類圖

在這裏插入圖片描述

Flyable.java

// 飛行的策略接口
public interface Flyable {
	public void fly();
}

Quackable.java

// 叫聲的策略接口
public interface Quackable {
	public void quack();
}

BadQuack.java

// 叫聲的具體策略
public class BadQuack implements Quackable{

	@Override
	public void quack() {
		System.out.println("BadQuack");
	}

}

BadFly.java

// 飛行的具體策略
public class BadFly implements Flyable{

	@Override
	public void fly() {
		System.out.println("BadFly");
	}
	
}

CantFly.java

// 飛行的具體策略
public class CantFly implements Flyable{

	@Override
	public void fly() {
		System.out.println("CantFly");
	}
	
}

CantQuack.java

// 叫聲的具體策略
public class CantQuack implements Quackable{

	@Override
	public void quack() {
		System.out.println("CantQuack");
	}

}

GoodFly.java

// 飛行的具體策略
public class GoodFly implements Flyable{

	@Override
	public void fly() {
		System.out.println("GoodFly");
	}
	
}

GoodQuack.java

// 叫聲的具體策略
public class GoodQuack implements Quackable{

	@Override
	public void quack() {
		System.out.println("GoodQuack");
	}

}

Duck.java

// 抽象鴨子類
public abstract class Duck {

	protected Flyable flyable;
	protected Quackable quackable;

	public void setFlyable(Flyable flyable) {
		this.flyable = flyable;
	}

	public void setQuackable(Quackable quackable) {
		this.quackable = quackable;
	}

	public void fly() {
		flyable.fly();
	}

	public void quack() {
		quackable.quack();
	}

	public abstract void display();
}

RealDuck.java

// 具體鴨子類
public class RealDuck extends Duck {

	public RealDuck() {
		flyable = new BadFly();
		quackable = new GoodQuack();
	}

	@Override
	public void display() {
		System.out.println("RealDuck");
	}

}

FackDuck.java

// 具體鴨子類
public class FackDuck extends Duck {

	public FackDuck() {
		flyable = new CantFly();
		quackable = new CantQuack();
	}

	@Override
	public void display() {
		System.out.println("FackDuck");

	}

}

測試Main.java

public class Main {
	public static void main(String[] args) {
		RealDuck realDuck = new RealDuck();
		realDuck.fly();
		realDuck.quack();
		System.out.println();
		FackDuck fackDuck = new FackDuck();
		fackDuck.fly();
		fackDuck.quack();
	}
}

輸出結果

在這裏插入圖片描述

6. 策略模式的注意事項和細節

  1. 策略模式的關鍵是:分析項目中變化部分與不變部分

  2. 策略模式的核心思想是:多用組合/聚合 少用繼承;用行爲類組合,而不是行爲的繼承。更有彈性

  3. 體現了“對修改關閉,對擴展開放”原則,客戶端增加行爲不用修改原有代碼,只要添加一種策略(或者行爲)即可,避免了使用多重轉移語句(if…else if…else)

  4. 提供了可以替換繼承關係的辦法: 策略模式將算法封裝在獨立的Strategy類中使得你可以獨立於其Context改變它,使它易於切換、易於理解、易於擴展

  5. 需要注意的是:每添加一個策略就要增加一個類,當策略過多是會導致類數目龐大

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章