`

观察者模式和模拟wow插件的例子

阅读更多
观察者模式的定义:在对象之间定义一对多的依赖,当一个对象改变状态时,依赖它的对象都会收到通知,并自动更新。

说白了就像是:有一群人订了同一家报纸,当这个报纸出新版的时候,会派报童给每个订阅了自己的人一份最新的报纸,然后不同的订阅人收到报纸后,自己处理,可以看看新闻,可以叠成飞机,可以用来防止上厕所时没带纸。。。订阅者收到报纸后怎么样,已经不管这家报纸发行商的事了。
订阅人可以取消订阅,没订阅的人也可以加入订阅的行列。

WOW扫盲,写给没玩过WOW的java人们:
WOW:魔兽世界
BOSS:这个大家都知道,每个游戏都有BOSS,就是个怪物的首领
TANK:也就是大家常说的肉盾,把BOSS的仇恨吸引到自己身上来,好让其他人打BOSS
DPS:打手,BOSS打TANK,DPS打BOSS
Healther:治疗,俗称奶妈,BOSS打TANK,奶妈给TANK加血。


现在用这种模式来模拟一个WOW的插件。
假设,WOW中有一个BOSS,他的技能分两个阶段。
第一阶段的时候,只用TANK拉好了,DPS们只管打就是了,奶妈治疗TANK。
第二阶段的时候,BOSS会在地面上方火焰,TANK依然是拉好BOSS,但需要躲地上的火焰,DPS们依然是打BOSS,也需要躲火焰,奶妈这个时候不但要为TANK加血,也要为DPS加血(有的DPS可能被火烧到)。

我们要做的东西,就是为队长写一个插件,让这个插件可以自动给队里的每个角色分配任务。
我们希望BOSS在第一阶段的时候,奶妈可以自动收到一个提示“请全力治疗Tank。”,而DPS收到的提示却是“请全力输出BOSS。”
插件为每个玩家配置一个发信的工具,为了方便就叫话筒吧,话筒去对玩家发送消息。

我们可以把BOSS看做是一个被观察的主题,而小队中所有玩家对应的话筒都是观察者。一但BOSS进入了第一阶段,也就是BOSS状态变了,那么所有观察者(也就是话筒)都会受到相应的通知,并对自己对应的玩家发送消息。


现在看代码:
package com.subject;

import com.observer.I_Observer;
//被观察的主题的接口
public interface I_Subject {
	//注册一个观察者
	public void registerObserver(I_Observer o);
	//删除一个观察者
	public void removeObserver(I_Observer o);
	//通知所有观察者
	public void notifyObserver();
}



package com.subject;

import java.util.ArrayList;

import com.observer.I_Observer;
//假设这是插件用来检测BOSS状态的监听器。这里并没有实现监听功能。
public class BossListener implements I_Subject {
	ArrayList<I_Observer> listOfObserver;
	int status;

	public BossListener() {
		listOfObserver = new ArrayList<I_Observer>();
		status = 1;
	}

	public int getStatus() {
		return status;
	}
	
	public void setStatus(int status) {
		
		this.status = status;
		this.notifyObserver();
	}
	//通知所有观察者,并告诉观察者自己当前的状态
	@Override
	public void notifyObserver() {
		for (I_Observer o : listOfObserver) {
			o.update(this.status);
		}
	}

	@Override
	public void registerObserver(I_Observer o) {
		this.listOfObserver.add(o);
	}

	@Override
	public void removeObserver(I_Observer o) {
		int index = this.listOfObserver.indexOf(o);
		if (index >= 0) {
			this.listOfObserver.remove(index);
		}
	}

}



package com.observer;
//观察者的接口
public interface I_Observer {
	//状态改变时执行的动作
	public void update(int status);
}



package com.observer;

public abstract class Player implements I_Observer {
	//玩家的名字
	String name;
	//在第一阶段时,对玩家的提示。
	String suggestion1;
	//在第二阶段时,对玩家的提示。
	String suggestion2;
	//在第三阶段时,对玩家的提示。
	String suggestion3;

	public String getSuggestion1() {
		return suggestion1;
	}

	public void setSuggestion1(String suggestion1) {
		this.suggestion1 = suggestion1;
	}

	public String getSuggestion2() {
		return suggestion2;
	}

	public void setSuggestion2(String suggestion2) {
		this.suggestion2 = suggestion2;
	}

	public String getSuggestion3() {
		return suggestion3;
	}

	public void setSuggestion3(String suggestion3) {
		this.suggestion3 = suggestion3;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
	//根据不同阶段,发送不同的通知消息。
	public void update(int status) {
		if (status == 1) {
			System.out.println("插件提示:Boss进入了第一阶段," + this.getName()
					+ suggestion1);
		} else if (status == 2) {
			System.out.println("插件提示:Boss进入了第二阶段," + this.getName()
					+ suggestion2);
		} else if (status == 3) {
			System.out.println("插件提示:Boss已经死亡,恭喜" + suggestion3);
		}
	}


}



package com.observer;

public class Tank extends Player {
	
	public Tank(String name) {
		this.name = name;
		this.name=name;
		this.suggestion1 = "请保持BOSS的仇恨";
		this.suggestion2 = "请保持BOSS的仇恨并躲好地上的火焰。";
		this.suggestion3 = ",BOSS已经死亡。";
	}
	//通知的逻辑已经在父类写过了,这里只用更改自己通知时的消息就行了
	@Override
	public void update(int status) {
		super.update(status);
	}
	
}



package com.observer;

public class DPS extends Player {
	public DPS(String name)
	{
		this.name=name;
		this.suggestion1 = "请全力输出BOSS。";
		this.suggestion2 = "请全力输出BOSS并躲好地上的火焰。";
		this.suggestion3 = ",BOSS已经死亡。";
	}

	@Override
	public void update(int status) {
		super.update(status);
	}

}



package com.observer;

public class Healther extends Player {
	public Healther(String name) {
		this.name = name;
		this.suggestion1 = "请全力治疗Tank。";
		this.suggestion2 = "请对全团治疗,保持团血在百分之50以上。";
		this.suggestion3 = ",BOSS已经死亡。";
	}

	@Override
	public void update(int status) {
		super.update(status);
	}

}



测试类:
package com.test;

import com.observer.DPS;
import com.observer.Healther;
import com.observer.Tank;
import com.subject.BossListener;

public class Test {
	public static void main(String[] args) {
		BossListener listener =new BossListener();
		listener.registerObserver(new Tank("MT"));
		listener.registerObserver(new Tank("2T"));
		listener.registerObserver(new DPS("DPS1"));
		listener.registerObserver(new Healther("Healther1"));
		listener.setStatus(1);
		listener.setStatus(2);
		listener.setStatus(3);
		
	}
}



插件提示:Boss进入了第一阶段,MT请保持BOSS的仇恨
插件提示:Boss进入了第一阶段,2T请保持BOSS的仇恨
插件提示:Boss进入了第一阶段,DPS1请全力输出BOSS。
插件提示:Boss进入了第一阶段,Healther1请全力治疗Tank。
插件提示:Boss进入了第二阶段,MT请保持BOSS的仇恨并躲好地上的火焰。
插件提示:Boss进入了第二阶段,2T请保持BOSS的仇恨并躲好地上的火焰。
插件提示:Boss进入了第二阶段,DPS1请全力输出BOSS并躲好地上的火焰。
插件提示:Boss进入了第二阶段,Healther1请对全团治疗,保持团血在百分之50以上。
插件提示:Boss已经死亡,恭喜,BOSS已经死亡。
插件提示:Boss已经死亡,恭喜,BOSS已经死亡。
插件提示:Boss已经死亡,恭喜,BOSS已经死亡。
插件提示:Boss已经死亡,恭喜,BOSS已经死亡。



看完这些代码和执行结果,再回头看一下观察者模式的定义:
在对象之间定义一对多的依赖,当一个对象改变状态时,依赖它的对象都会收到通知,并自动更新。

多个观察者依赖同一个BOSS监听器,BOSS监听器监听到BOSS状态改变,则通知所有话筒,这些观察者做出了各自的反应。


当然,写这个主要是为了巩固观察者模式,WOW插件只是个例子,真正的WOW插件是很复杂的。。。

最后,身为一个WOWer向所有WOW插件开发者敬礼。
1
0
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics