小灰 程序员小灰
————— 第二天 —————
————————————
场景1:游戏操作界面
在一个小游戏中,包含一个简单的操作界面,界面上有两个按钮:道具和魔法。
如果点击“道具”按钮,游戏里的主角会使用道具;如果点击“魔法”按钮,游戏里的主角会使用魔法。
如何让主角实时接收到点击按钮的事件,并做出相应的行动呢?
场景2:游戏迷宫
同样在这个小游戏里,有一个迷宫,迷宫里有怪物、陷阱和宝物。
一旦主角移动到怪物的有效范围,怪物会袭击主角;主角移动到陷阱的有效范围,陷阱会困住主角;主角移动到宝物的有效范围,宝物会为主角加血。
如何让主角移动的事件被怪物、陷阱、道具感知到,并做出正确的反应?
public class Hero {
//怪物
Monster monster;
//陷阱
Trap trap;
//宝物
Treasure treasure;
public void move(){
System.out.println("主角向前移动");
//主角移动时,分别通知怪物、陷阱和宝物对象
monster.update();
trap.update();
treasure.update();
}
}
在上面的UML图中,主要有两组实体对象,一组是观察者,一组是被观察者。所有的观察者,都实现了Observer接口;所有的被观察者,都继承自Subject抽象类。
Subject类的成员OberverList,存储着已注册的观察者,当事件发生时,会通知列表中的所有观察者。需要注意的是,OberverList所依赖的是抽象的Observer接口,这样就避免了观察者与被观察者的紧耦合。
//观察者
public interface Observer {
public void update();
}
//被观察者
abstract public class Subject {
private List<Observer> observerList = new ArrayList<Observer>();
public void attachObserver(Observer observer) {
observerList.add(observer);
}
public void detachObserver(Observer observer){
observerList.remove(observer);
}
public void notifyObservers(){
for (Observer observer: observerList){
observer.update();
}
}
}
//怪物
public class Monster implements Observer {
@Override
public void update() {
if(inRange()){
System.out.println("怪物 对主角***!");
}
}
private boolean inRange(){
//判断主角是否在自己的影响范围内,这里忽略细节,直接返回true
return true;
}
}
//陷阱
public class Trap implements Observer {
@Override
public void update() {
if(inRange()){
System.out.println("陷阱 困住主角!");
}
}
private boolean inRange(){
//判断主角是否在自己的影响范围内,这里忽略细节,直接返回true
return true;
}
}
//宝物
public class Treasure implements Observer {
@Override
public void update() {
if(inRange()){
System.out.println("宝物 为主角加血!");
}
}
private boolean inRange(){
//判断主角是否在自己的影响范围内,这里忽略细节,直接返回true
return true;
}
}
上面代码中,每一个具体观察者类都实现了update方法,这是事件触发的回调方法,包含了具体观察者对事件的不同反应。
public class Hero extends Subject{
void move(){
System.out.println("主角向前移动");
notifyObservers();
}
}
当主角移动时,通知所有已注册的观察者,执行具体观察者各自的update方法。
public class Client {
public static void main(String[] args) {
//初始化对象
Hero hero = new Hero();
Monster monster = new Monster();
Trap trap = new Trap();
Treasure treasure = new Treasure();
//注册观察者
hero.attachObserver(monster);
hero.attachObserver(trap);
hero.attachObserver(treasure);
//移动事件
hero.move();
}
}
代码输出如下:
主角向前移动
怪物 对主角***!
陷阱 困住主角!
宝物 为主角加血!