红色警戒--间谍
间谍是个神奇的角色,可以偷到敌人的矿厂、军营、坦克厂。偷到敌人军营的时,所有的一级兵都能升级成二级,爽歪了。
所以跟哥们打仗的时候就使劲造狗,狗能识别出间谍,主动出击。
有时忘了造狗,眼瞅着敌人的间谍大摇大摆地进入军营,着实郁闷。
间谍进入军营做了什么呢?
假设现在有一个两级的美国大兵、一个伞兵那这个间谍应该怎么做呢。
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 List<Solider> soliderList; public Sky(){ soliderList = new ArrayList<Solider>(); 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将关键的方法保护起来了,别人用不着。那我们就只能自己实现这个模式了。有兴趣的可以去看看这两了支持类的源码。