圖解Java設計模式之策略模式

編寫鴨子項目,具體要求以下 :

1)有各類鴨子(好比 野鴨、北京鴨、水鴨等)鴨子有各類行爲,好比叫、飛行等等。
2)顯示鴨子的信息算法

傳統方案解決鴨子問題的分析和代碼實現

1)傳統的設計方案(類圖)
在這裏插入圖片描述編程

package com.example.demo.dtrategy;

public abstract class Duck {
	
	public Duck() {}
	
	// 顯示鴨子信息
	public abstract void display();
	
	public void quack() {
		System.out.println("鴨子嘎嘎叫~~~");
	}
	
	public void swim() {
		System.out.println("鴨子會游泳~~~");
	}
	
	public void fly() {
		System.out.println("鴨子會飛~~~");
	}

}
package com.example.demo.dtrategy;

public class PekingDuck extends Duck {

	@Override
	public void display() {
		// TODO Auto-generated method stub
		System.out.println("~~ 北京鴨 ~~");
	}
	
	@Override
	public void fly() {
		// TODO Auto-generated method stub
		System.out.println("北京鴨不能飛翔");
	}

}
package com.example.demo.dtrategy;

public class ToyDuck extends Duck {

	@Override
	public void display() {
		// TODO Auto-generated method stub
		System.out.println("玩具鴨");
	}

	//須要重寫父類的全部方法
	public void quack() { 
		System.out.println("玩具鴨不能叫~~");
	}
	public void swim() { 
		System.out.println("玩具鴨不會游泳~~");
	}
	public void fly() { 
		System.out.println("玩具鴨不會飛翔~~~");
	}
}
package com.example.demo.dtrategy;

public class WildDuck extends Duck {

	@Override
	public void display() {
		// TODO Auto-generated method stub
		System.out.println(" 這是野鴨 ");
	}

}

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

1)其它鴨子,都繼承類Duck類,因此fly讓全部子類都會飛類,這是不正確的。
2)上面說的1的問題,實際上是繼承帶來的問題 :對類的局部改動,尤爲超類的局部改動,會影響其它部分。會有溢出效應。
3)爲了改進1問題,咱們能夠經過覆蓋fly 方法來解決 - 》覆蓋解決
4)問題又來來,若是咱們有一個玩具鴨子ToyDuck,這樣就須要ToyDuck去覆蓋Duck的全部實現的方法 = 》策略模式(strategy pattern)設計模式

策略模式基本介紹

1)策略模式(Strategy Pattern)中,定義算法族,分別封裝起來,讓他們之間能夠相互替換,此模式讓算法的變化獨立於使用算法的客戶。
2)這算法體現來幾個設計原則,第1、把變化的代碼從不變的代碼中分離出來;第2、針對接口編程而不是具體類(定義來策略接口):第3、多組合/聚合,少用繼承(客戶經過組合方式使用策略)。ide

策略模式的原理類圖

在這裏插入圖片描述
說明 :從上圖能夠看到,客戶端context 有成員變量 strategy 或者其它的策略接口,至於須要使用到那個策略,咱們能夠在構造器中指定。源碼分析

策略模式解決鴨子問題

1)應用實例要求
編寫程序完成前面的鴨子項目,要求使用策略模式
2)類圖
在這裏插入圖片描述this

package com.example.demo.dtrategy.improe;

public interface FlyBehavior {

	void fly(); // 子類具體實現
}
package com.example.demo.dtrategy.improe;

public interface QuackBehavior {

}
package com.example.demo.dtrategy.improe;

public class BadFlyBehavior implements FlyBehavior {

	@Override
	public void fly() {
		// TODO Auto-generated method stub
		System.out.println(" 飛翔技術通常 ");
	}

}
package com.example.demo.dtrategy.improe;

public abstract class Duck {
	
	//屬性, 策略接口
	FlyBehavior flyBehavior; 
	//其它屬性<->策略接口 
	QuackBehavior quackBehavior;

	public Duck() {}
	
	// 顯示鴨子信息
	public abstract void display();
	
	public void quack() {
		System.out.println("鴨子嘎嘎叫~~~");
	}
	
	public void swim() {
		System.out.println("鴨子會游泳~~~");
	}
	
	public void fly() {
		// 改進
		if(flyBehavior != null) {
			flyBehavior.fly();
		}
	}

	public FlyBehavior getFlyBehavior() {
		return flyBehavior;
	}

	public void setFlyBehavior(FlyBehavior flyBehavior) {
		this.flyBehavior = flyBehavior;
	}

	public QuackBehavior getQuackBehavior() {
		return quackBehavior;
	}

	public void setQuackBehavior(QuackBehavior quackBehavior) {
		this.quackBehavior = quackBehavior;
	}
	
	
}
package com.example.demo.dtrategy.improe;

public class GoodFlyBehavior implements FlyBehavior {

	@Override
	public void fly() {
		// TODO Auto-generated method stub
		System.out.println(" 飛翔技術高超 ~~~");
	}

}
package com.example.demo.dtrategy.improe;

public class NoFlyBehavior implements FlyBehavior {

	@Override
	public void fly() {
		// TODO Auto-generated method stub
		System.out.println(" 不會飛翔 ");
	}

}
package com.example.demo.dtrategy.improe;

public class PekingDuck extends Duck {
	
	//假如北京鴨能夠飛翔,可是飛翔技術通常 
	public PekingDuck() {
		// TODO Auto-generated constructor stub 
		flyBehavior = new BadFlyBehavior();
	}

	@Override
	public void display() {
		// TODO Auto-generated method stub
		System.out.println("~~北京鴨~~~");
	}

}
package com.example.demo.dtrategy.improe;

public class ToyDuck extends Duck {
	
	public ToyDuck() {
		// TODO Auto-generated constructor stub 
		flyBehavior = new NoFlyBehavior();
	}

	@Override
	public void display() {
		// TODO Auto-generated method stub
		System.out.println("玩具鴨");
	}
	
	//須要重寫父類的全部方法
	public void quack() { 
		System.out.println("玩具鴨不能叫~~");
	}

	public void swim() { 
		System.out.println("玩具鴨不會游泳~~");
	}
}
package com.example.demo.dtrategy.improe;

public class WilDuck extends Duck {
	
	/**
	 * 構造器,傳入FlyBehavor 的對象
	 */
	public WilDuck() {
		flyBehavior = new GoodFlyBehavior();
	}

	@Override
	public void display() {
		// TODO Auto-generated method stub
		System.out.println(" 這是野鴨 ");
	}

}
package com.example.demo.dtrategy.improe;

public class Client {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		WilDuck wildDuck = new WilDuck(); 
		wildDuck.fly();//
		ToyDuck toyDuck = new ToyDuck(); 
		toyDuck.fly();
		PekingDuck pekingDuck = new PekingDuck(); 
		pekingDuck.fly();
		//動態改變某個對象的行爲, 北京鴨 不能飛 
		pekingDuck.setFlyBehavior(new NoFlyBehavior()); 
		System.out.println("北京鴨的實際飛翔能力");
	}

}

策略模式在JDK - Arrays 應用的源碼分析

在這裏插入圖片描述
說明:.net

  1. 實現了 Comparator 接口(策略接口) , 匿名類 對象 new Comparator(){…}
  2. 對象 new Comparator(){…} 就是實現了 策略接口 的對象
  3. public int compare(Integer o1, Integer o2){} 指定具體的處理方式

策略模式的注意實現和細節

1)策略模式的關鍵是 :分析項目中變化部分與不變部分
2)策略模式的核心思想是 :多用組合/聚合,少用繼承;用行爲類組合,而不是行爲的繼承。更有彈性。
3)體現了「開閉原則」。客戶端增長行爲不用修改原有代碼,只要添加一種策略(或者行爲)便可,避免了使用多重轉移語句(if…else if … else);
4)提供了能夠替換繼承關心的辦法 :策略模式將算法封裝在獨立的Strategy類中使得你能夠獨立於其Context改變它,使它易於切換、易於理解、易於擴展。
5)須要注意的是 :每添加一個策略就要增長一個類,當策略過可能是會致使類數目龐大。設計

相關文章
相關標籤/搜索