天天看點

軟體設計模式-簡介-政策模式-觀察者模式題外話軟體設計模式核心思想

題外話

部落客學習軟體設計模式參考的是head first軟體設計模式這本書 例題代碼是本人自己所敲(僅供參考 裡面并不是與書中完全一緻 而是部落客結合自己的經驗而設定的)

軟體設計模式核心思想

軟體設計模式的一個最核心,最基礎的思想是将會變化的部分取出來并進行封裝 這樣的話以後需要擴充 或需要進行改變的時候就很友善了, 而不至于影響到不需要變化的那部分。

軟體設計模式-簡介-政策模式-觀察者模式題外話軟體設計模式核心思想

第二個原則是我們針對的是面向接口程式設計 即我們不要針對具體的實作 就像造汽車 我們需要的是生産元件 組裝的組合有千萬種 但是元件是一定的! 是以我們是面向接口程式設計

軟體設計模式-簡介-政策模式-觀察者模式題外話軟體設計模式核心思想

例如經典的鴨子叫 針對飛和叫兩種行為 進行程式設計!

軟體設計模式-簡介-政策模式-觀察者模式題外話軟體設計模式核心思想

通過使用接口繼承 而不是針對鴨子類進行繼承 我們可以實作分離 這樣就實作最大幅度的代碼複用!

軟體設計模式-簡介-政策模式-觀察者模式題外話軟體設計模式核心思想

鴨子行為和多态的結合 通過在Duck加上兩個執行個體變量 這樣在運作時就會動态的改變鴨子狀态 然後我們實作兩個方法 裡面交給對應執行個體變量來操作!

軟體設計模式-簡介-政策模式-觀察者模式題外話軟體設計模式核心思想

鴨子例子通過委托的形式 交給了兩個行為類進行處理 這是對類的一種組合(compositoin) 而不是繼承,鴨子的行為并不是繼承而來! 而是與适當的對象組合而成 ** 本例中使用了委托行為類** 而不是讓鴨子繼承行為類! 将變化的部分我們通過組合的形式來近似于繼承~

軟體設計模式-簡介-政策模式-觀察者模式題外話軟體設計模式核心思想

政策模式

我們的模拟鴨子的例子實際上就是使用了政策模式 我們不難看出來 政策模式是針對行為進行抽象的一種行為 即通過增加新的行為 而不用修改實作即可使用新的行為!

軟體設計模式-簡介-政策模式-觀察者模式題外話軟體設計模式核心思想

鴨子執行個體代碼

鴨子示例代碼如下所示

/**  
* @Title: SimulateDuck.java  
* @Package   
* @Description: TODO(用一句話描述該檔案做什麼)  
* @author Lustre  
* @date 2019年12月7日  
* @version V1.0  
*/
/**
* @author Nigel
* @version 建立檔案時間:2019年12月7日 下午11:25:08
*/
/**  
* @ClassName: SimulateDuck  
* @Description: TODO(這裡用一句話描述這個類的作用)  
* @author Nigel  
* @date 2019年12月7日  
*    
*/

/**
 * 
* @ClassName: flyBehavior  
* @Description: 鴨子飛行行為 
* @author Nigel  
* @date 2019年12月8日  
*
 */
interface FlyBehavior {
	void flyAction();
}

class NormalFly implements FlyBehavior{

	@Override
	public void flyAction() {
		// TODO Auto-generated method stub
		System.out.println("normal fly action!");
	}
	
}

class RocketFly implements FlyBehavior {

	@Override
	public void flyAction() {
		// TODO Auto-generated method stub
		System.out.println("I am now in a rocket flight!");
	}
	
}

class CouldNotFly implements FlyBehavior {

	@Override
	public void flyAction() {
		// TODO Auto-generated method stub
		System.out.println("can not fly");
	}
	
}

interface QuarkBehavior {
	void quarkAction();
}

class CouldNotQuark implements QuarkBehavior{

	@Override
	public void quarkAction() {
		// TODO Auto-generated method stub
		System.out.println("I cound not quark!");
	}
	
}

class NormalQuark implements QuarkBehavior {

	@Override
	public void quarkAction() {
		// TODO Auto-generated method stub
		System.out.println("I can quark normally!");
	}
	
}

abstract class Duck {
	//動态運作時對這兩個行為進行改變!
	//我們通過組合兩個動态執行個體變量 實作動态時運作和多态行為
	FlyBehavior flyBehavior;
	QuarkBehavior quarkBehavior;
	
	
	

	/**  
	* @Title: performFlyAction  
	* @Description: TODO      
	* @return void    
	* @throws
	*/  
	public void performFlyAction() {
		flyBehavior.flyAction();
	}

	/**  
	* @Title: performQuarkAction  
	* @Description: TODO      
	* @return void    
	* @throws
	*/  
	 public void performQuarkAction() {
		 quarkBehavior.quarkAction();
	 }
	 
	//設定getter 和 setter方法使得能動态改變鴨子的行為
	public FlyBehavior getFlyBehavior() {
		return flyBehavior;
	}

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

	public QuarkBehavior getQuarkBehavior() {
		return quarkBehavior;
	}

	public void setQuarkBehavior(QuarkBehavior quarkBehavior) {
		this.quarkBehavior = quarkBehavior;
	}

	abstract void display();
	
	
}

class RubberDuck extends Duck {

	public RubberDuck() {
		//初始化執行個體變量
		flyBehavior = new CouldNotFly();
		quarkBehavior = new CouldNotQuark();
	}
	
	void display() {
		// TODO Auto-generated method stub
		System.out.println("This is a rubber duck!");
	}
	
	
}


public class SimulateDuck {
	public static void main(String[] args) {
		Duck rubberDuck = new RubberDuck();
		//讓橡皮鴨發出叫和飛行這兩種動作
		rubberDuck.performFlyAction();
		rubberDuck.performQuarkAction();
		rubberDuck.display();
		//讓橡皮鴨增加火箭飛行的行為
		rubberDuck.setFlyBehavior(new RocketFly());
		rubberDuck.performFlyAction();
		
	}
}



           

角色扮演遊戲的示例代碼

執行個體代碼如下所示

/**  
* @Title: MultipleWeaponTest.java  
* @Package   
* @Description: TODO(用一句話描述該檔案做什麼)  
* @author Lustre  
* @date 2019年12月8日  
* @version V1.0  
*/
/**
* @author Nigel
* @version 建立檔案時間:2019年12月8日 上午11:09:15
*/

/**
 * 
* @InterfaceName: WeaponBehavior  
* @Description:将武器視為一種行為 即我們不應該針對具體的角色程式設計 而是根據角色的行為 由于每名角色有它自己的武器行為 是以針對不同的武器進行抽象
* @author Nigel  
* @date 2019年12月8日  
*
 */
interface WeaponBehavior {
	String useWeapon();
}

class KnifeBehavior implements WeaponBehavior{

	@Override
	public String useWeapon() {
		// TODO Auto-generated method stub
		String string = "正在使用Knife";
		return string;
	}
}

class BowAndArrowBehavior implements WeaponBehavior {

	@Override
	public String useWeapon() {
		// TODO Auto-generated method stub
		String string = "正在使用BowAndArrow";
		return string;
	}
	
}

class AxeBehavior implements WeaponBehavior {

	@Override
	public String useWeapon() {
		// TODO Auto-generated method stub
		String string = "正在使用Axe";
		return string;
	}
}

class SwordBehavior implements WeaponBehavior {

	@Override
	public String useWeapon() {
		// TODO Auto-generated method stub
		String string = "正在使用Sword";
		return string;
	}
}

/**
 * 
* @ClassName: Character  
* @Description: 角色基類
* @author Nigel  
* @date 2019年12月8日  
*
 */
abstract class Character {
	protected WeaponBehavior weaponBehavior;
	protected String characterName = this.getClass().getName();
	/**
	 * 
	* @Title: fight  
	* @Description: 和具體的某個人進行打鬥操作 
	* @param character    
	* @return void    
	* @throws
	 */
	void fight(Character character) {
		if (character != null) {
			System.out.println( characterName  + weaponBehavior.useWeapon() + "和" + character.characterName + character.getWeaponBehavior().useWeapon() + "進行打鬥" );
		} else {
			System.out.println("此時并沒有和任何人進行打鬥");
		}
		
	}
	
	void holdingWeapon() {
		System.out.println( characterName + weaponBehavior.useWeapon() );
	}
	
	/**
	 * 
	* @Title: getWeaponBehavior  
	* @Description: 角色可以更換所使用的武器 是以使用一個getter和 setter方法來變更對應的武器
	* @return    
	* @return WeaponBehavior    
	* @throws
	 */
	public WeaponBehavior getWeaponBehavior() {
		return weaponBehavior;
	}

	public void setWeaponBehavior(WeaponBehavior weaponBehavior) {
		this.weaponBehavior = weaponBehavior;
	}
}

class Queen extends Character {

	/**
	 * 
	* 建立一個新的執行個體 Queen.  
	*
	 */
	public Queen() {
		this.weaponBehavior = new AxeBehavior();
	}
}

class King extends Character {
	
	public King() {
		this.weaponBehavior = new KnifeBehavior();
	}
}

/**  
* @ClassName: MultipleWeaponTest  
* @Description: TODO(這裡用一句話描述這個類的作用)  
* @author Nigel  
* @date 2019年12月8日  
*    
*/
public class MultipleWeaponTest {

	/**  
	* @Title: main  
	* @Description: TODO  
	* @param args    
	* @return void    
	* @throws
	*/
	public static void main(String[] args) {
		//初始化一個king對象
		Character myKing = new King();
		//初始化一個queen對象
		Character myQueen = new Queen();
		
		//進行行為識别
		myKing.holdingWeapon();
		myQueen.holdingWeapon();
		
		//進行打鬥測試
		myKing.fight(myQueen);
		//myQueen.fight(myKing);
		
		//更換武器
		myKing.setWeaponBehavior(new BowAndArrowBehavior());
		myKing.fight(myQueen);
	}

}
           

觀察者模式

給出一個觀察者模式的應用場景 即多個受體依賴于一個主體的時候 我們就可以使用主體-觀察者這個設計模式 即Observer-Subject model 下面的應用場景是有一個氣象站(起到資料廣播的作用)和n個氣象顯示裝置 現在要求氣象裝置能實時的接收氣象站資料的更新狀況 此時就是一對多的一個依賴關系 我們通過一個抽象的Observer和Subject接口來實作抽象 Subject接口實作注冊 删除 通知功能 在通知功能中我們通過周遊來調用抽象的Observer.update()接口實作統一 具體的實作則是由觀察者實作。 這樣做到了一個**所謂的松耦合 即低耦合 **

觀察者模式的示例代碼見下

import java.util.ArrayList;
import java.util.List;

/**  
* @Title: WhetherConditionTest.java  
* @Package   
* @Description: TODO(用一句話描述該檔案做什麼)  
* @author Lustre  
* @date 2019年12月8日  
* @version V1.0  
*/
/**
* @author Nigel
* @version 建立檔案時間:2019年12月8日 下午2:29:41
*/

/**
 * 
* @ClassName: Subject  
* @Description: 主體資料
* @author Nigel  
* @date 2019年12月8日  
*
 */
interface Subject {
	//可以設定天氣狀況
	void setWhetherInfomationAndNotify(WhetherBean whether);
	//注冊成為觀察者 則在更新的時候會即時接受到資料
	void RegisterObserver(Observer observer);
	//可以進行移除操作
	void RemoveObserver(Observer observer);
	//在資料變換的時候及時通知觀察者進行資料的更新操作
	void NotifyObserver();
}

/**
 * 
* @ClassName: Observer  
* @Description: 觀察者 這裡我們僅僅需要實作update接口即可
* @author Nigel  
* @date 2019年12月8日  
*
 */
interface Observer {
	void update(Object object);
	void setSubject(Subject subject);
	void removeSelf();
}


/**
 * 
* @ClassName: DisplayData  
* @Description: 由于在這個example中 我們想要展示對應的資料資訊 是以也需要繼承的"布告闆"實作這個display接口
* @author Nigel  
* @date 2019年12月8日  
*
 */
interface DisplayData {
	/**  
	* @Title: displayStatisticsBoardInfo  
	* @Description: TODO  
	* @param whether    
	* @return void    
	* @throws
	*/  
	void display(Object object);
}


class WhetherData implements Subject {
	private List<Observer> observers;
	private WhetherBean whether;//我們隻需要維護一個WhetherBean對象即可 将所有的資料放進去 update的時候由程式自己取它自己想要的資料
	
	@Override
	public void setWhetherInfomationAndNotify(WhetherBean whether) {
		//首先更新資料
		this.whether = whether;
		//然後通知所有觀察者資料進行了更新的操作
		NotifyObserver();
	}
	
	/**  
	* 建立一個新的執行個體 WhetherData.  
	*    
	*/
	public WhetherData() {
		//建立一個清單
		observers = new ArrayList<Observer>();
	}

	@Override
	public void RegisterObserver(Observer observer) {
		// TODO Auto-generated method stub
		//由測試程式進行調用 我們需要将新的觀察者加入到收聽者那部分去
		observers.add(observer);
		//然後将主體傳送給觀察者
		observer.setSubject(this);
		System.out.println("成功添加一個觀察者");
	}

	@Override
	public void RemoveObserver(Observer observer) {
		// TODO Auto-generated method stub
		observers.remove(observer);
	}

	@Override
	public void NotifyObserver() {
		// 周遊每一個觀察進行資料的更新!
		for (int i = 0; i < observers.size(); i++) {
			Observer observer = observers.get(i);
			//通過統一的update接口實作資料的更新操作
			observer.update(whether);
		}
	}
}

/**
 * 
* @ClassName: ConcreteDisplayData  
* @Description: 展示具體的資料資訊 作為一個視圖層來使用 這裡我們借鑒了MVC的使用 因為展示也是一個不斷變化的部分 是以我們把它也單獨抽象了出來
* @author Nigel  
* @date 2019年12月8日  
*
 */
class ConcreteDisplayData implements DisplayData{

	@Override
	public void display(Object whether) {
		//這裡簡單的在Whether中寫了個toString方法 然後進行列印操作
		System.out.println(whether);
	}
	
}

class StatisticsBoard implements Observer {
	//維護一個bean對象和一個資料展示對象
	private WhetherBean whether;
	private DisplayData display = new ConcreteDisplayData();
	private Subject whetherSubject;
	
	/**
	* <p>Title: update</p>  
	* <p>Description: 資料更新及展示功能
	* @see Observer#update()  
	*/  
	@Override
	public void update(Object whether) {
		//由監聽者選擇從Bean對象中取出哪些資料 而Subject主題對象隻需要一股腦的将所有資料放進去即可
		this.whether = (WhetherBean) whether;
		//由display負責展示
		display.display(whether);
	}

	/**
	* <p>Title: setSubject</p>  
	* <p>Description: </p>  
	* @param subject  
	* @see Observer#setSubject(Subject)  
	*/  
	@Override
	public void setSubject(Subject subject) {
		// TODO Auto-generated method stub
		whetherSubject = subject;
	}

	/**
	* <p>Title: removeSelf</p>  
	* <p>Description: </p>    
	* @see Observer#removeSelf()  
	*/  
	@Override
	public void removeSelf() {
		// 删除自己
		whetherSubject.RemoveObserver(this);
	}

}

/**  
* @ClassName: WhetherConditionTest  
* @Description: TODO(這裡用一句話描述這個類的作用)  
* @author Nigel  
* @date 2019年12月8日  
*    
*/
public class WhetherConditionTest {

	/**  
	* @Title: main  
	* @Description: TODO  
	* @param args    
	* @return void    
	* @throws
	*/
	public static void main(String[] args) {
		//用于測試Subject 和  Observer 的功能
		Float temperature = 38.6F;
		Float humidity = new Float(30.9);
		WhetherBean testWhetherBean = new WhetherBean();
		//設定測試的bean對象
		testWhetherBean.setHumidity(humidity);
		testWhetherBean.setTemperature(temperature);
		//建立一個Observer對象
		Observer testObserver = new StatisticsBoard();
		//測試Subject對象
		System.out.println("沒有監聽者的情況:");
		Subject testWhetherData = new WhetherData();
		testWhetherData.setWhetherInfomationAndNotify(testWhetherBean);
		//加入一個監聽者
		System.out.println("加入一個監聽者之後:");
		testWhetherData.RegisterObserver(testObserver);
		testWhetherData.setWhetherInfomationAndNotify(testWhetherBean);
		//測試資料的更新
		System.out.println("測試對資料進行更改操作:");
		temperature = 38.6F + 3F;
		humidity = new Float(324.9);
		testWhetherBean.setHumidity(humidity);
		testWhetherBean.setTemperature(temperature);
		testWhetherData.setWhetherInfomationAndNotify(testWhetherBean);
		//再次增加一個觀察者
		System.out.println("再次增加一個觀察者:");
		Observer testObserver2 = new StatisticsBoard();
		testWhetherData.RegisterObserver(testObserver2);//添加到觀察者清單
		testWhetherData.setWhetherInfomationAndNotify(testWhetherBean);
		//删除一個觀察者 由觀察者自身想退出觀察!
		System.out.println("由觀察者自身進行退出觀察操作:");
		testObserver2.removeSelf();
		testWhetherData.setWhetherInfomationAndNotify(testWhetherBean); //此時再次更新
		//由主體資料将觀察者進行移除
		System.out.println("由主體資料将觀察者進行移除(此時移除後更新發現沒有确實成功的移除了一個觀察者):");
		testWhetherData.RemoveObserver(testObserver);
		testWhetherData.setWhetherInfomationAndNotify(testWhetherBean); //此時再次更新
		
	}

}