天天看点

软件设计模式-简介-策略模式-观察者模式题外话软件设计模式核心思想

题外话

博主学习软件设计模式参考的是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); //此时再次更新
		
	}

}