红色警戒--间谍
间谍是个神奇的角色,可以偷到敌人的矿厂、军营、坦克厂。偷到敌人军营的时,所有的一级兵都能升级成二级,爽歪了。
所以跟哥们打仗的时候就使劲造狗,狗能识别出间谍,主动出击。
有时忘了造狗,眼瞅着敌人的间谍大摇大摆地进入军营,着实郁闷。
间谍进入军营做了什么呢?
假设现在有一个两级的美国大兵、一个伞兵那这个间谍应该怎么做呢。
public void interAnBarracks(){ System.out.println("间谍进入了军营"); footSolider1.partrol(); footSolider2.partrol(); liberationArmy1.partrol(); }
傻子都能看出来,这有问题啊,如果间谍进入军营之前有早出一个兵来怎么办?改代码么?
显然不行。
那我在间谍这里维护一个SoliderList 然后游戏中维护这个List,新造出一个兵来就加入到List中,兵升级了就从List中移除,怎么样?
累不累啊,游戏要时刻关心着当前有多少兵,有一个兵升级了,就赶紧去移除一下。真是操碎了心啊。
那到底该怎么办呢,别急,我们先把观察者模式的概念提出来。
观察者模式的目的是提供一种对象设计,让主题和观察者之间松耦合,使得对象之间的互相依赖降到最低。
这又是一条设计原则:
找出应用中可能需要变化之处,把他们独立出来,不要和那些不需要变化的代码混在一起。
现在我们得出设计方法:在间谍那里维护一份名单,大兵可以注册进这个名单(新来的大兵),也可以从名单中申请退出(大兵升级了)。间谍偷兵营成功后,就通知名单的人,让他们升级。
package com.zzl.designpattern.strategy;import com.zzl.designpattern.observer.Sky;public abstract class Solider { /** * 行为类 */ IFireable fireable; /** * 间谍 */ Sky sky; /** * 冲刺 */ public void rush(String direction){ System.out.println("向 " + direction + " 冲刺"); } /** * 从间谍那里除名 */ public void unregisteSelf(){ sky.removeSolider(this); } /** * 升级 */ public abstract void partrol(); /** * 开火 */ public void fire(){ fireable.fire(); } /** * setFireable */ public void setFireable(IFireable fireable){ this.fireable = fireable; } public Sky getSky() { return sky; } public void setSky(Sky sky) { this.sky = sky; } }
package com.zzl.designpattern.strategy;import com.zzl.designpattern.observer.Sky;public class FootSolider extends Solider { public FootSolider(Sky sky){ fireable = new FireWithGun(); System.out.println("新建一个一级美国大兵"); this.sky = sky; sky.registerSolider(this); } @Override public void partrol() { System.out.println("美国大兵升级了!"); this.setFireable(new FireWithAK47()); unregisteSelf(); }}
package com.zzl.designpattern.strategy;import com.zzl.designpattern.observer.Sky;public class LiberationArmy extends Solider { public LiberationArmy(Sky sky){ fireable = new FireWithGun(); System.out.println("新建一个一级伞兵"); this.sky = sky; sky.registerSolider(this); } @Override public void partrol() { System.out.println("伞兵升级了!"); this.setFireable(new FireWithAK47()); unregisteSelf(); } }
package com.zzl.designpattern.observer;import java.util.ArrayList;import java.util.List;import com.zzl.designpattern.strategy.Solider;public class Sky { private ListsoliderList; public Sky(){ soliderList = new ArrayList (); System.out.println("新建一个间谍"); } public void interAnBarracks(){ System.out.println("间谍进入了军营"); notifyObservers(); } public void notifyObservers(){ for(Solider solider : soliderList){ solider.partrol(); } } public void registerSolider(Solider solider){ soliderList.add(solider); System.out.println("间谍的名单中新增了一名大兵"); } public void removeSolider(Solider solider){ int i = soliderList.indexOf(solider); if(i > 0){ soliderList.remove(i); System.out.println("间谍的名单中移除了一名大兵"); } } }
package com.zzl.designpattern.main;import com.zzl.designpattern.observer.Sky;import com.zzl.designpattern.strategy.FootSolider;import com.zzl.designpattern.strategy.LiberationArmy;import com.zzl.designpattern.strategy.Solider;public class Game { public static void main(String[] args) { Sky sky = new Sky(); Solider footSolider1 = new FootSolider(sky); Solider footSolider2 = new FootSolider(sky); Solider liberationArmy1 = new LiberationArmy(sky); Solider liberationArmy2 = new LiberationArmy(sky); liberationArmy2.fire(); liberationArmy2.partrol(); liberationArmy2.fire(); sky.interAnBarracks(); footSolider1.fire(); footSolider2.fire(); liberationArmy1.fire(); }}
故事是这样的,美国大兵1、美国大兵2走出兵营,伞兵1、伞兵2也都从天而降,他们出来的时候都在间谍那里注册了名字,伞兵2运气比较好,出来以后打死了一个敌人,于是荣升为二级兵,于是换了AK47,就从间谍那退出名单了。这会儿间谍偷了对方的兵营,于是全民狂欢,一级兵都升级为二级兵用上了AK47了,也都从间谍那除名了。输出是这样的:
新建一个间谍新建一个一级美国大兵间谍的名单中新增了一名大兵新建一个一级美国大兵间谍的名单中新增了一名大兵新建一个一级伞兵间谍的名单中新增了一名大兵新建一个一级伞兵间谍的名单中新增了一名大兵使用普通枪攻击伞兵升级了!间谍的名单中移除了一名大兵使用AK47攻击!间谍进入了军营美国大兵升级了!美国大兵升级了!间谍的名单中移除了一名大兵使用AK47攻击!使用AK47攻击!使用普通枪攻击
在JDK库中提供了一个观察者模式的内置支持,java.utl包中的Observer接口和Observable类,遗憾的是,被观察者是个抽象类,我们的间谍只能继承这个类,那就不能继承别的类了,那么根据我们的设计原则优先用组合怎么样呢,也不行,因为Observable将关键的方法保护起来了,别人用不着。那我们就只能自己实现这个模式了。有兴趣的可以去看看这两了支持类的源码。