参考这篇文章,很生动:https://zhuanlan.zhihu.com/p/158537313
有点像发布订阅,有不同之处,但是要实现的功能很像
举了一个游戏的例子
Hero类走格子,有怪物类,宝物类,走到格子时需要判断是否进入这些格子并且产生效果。
传统想法之一(拉取):怪物类隔100ms判断一次,但这样一直空转
传统想法之二(推送):把几个类都写到Hero类中了,每次Hero类移动时做判断
观察者模式:
观察者:实现Observer接口(怪物类,宝物类),主要功能就是update
被观察者:继承Subject抽象类(Hero),有一个ObserverList,当需要更新时,notify观察者
逻辑:被观察者移动--notify观察者--观察者更新
代码:
观察者
//观察者 接口 public interface Observer { public void update(); } //怪物 public class Monster 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; } }
被观察者:
//被观察者 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(); } } } //实际被观察者,继承Subject类 public class Hero extends Subject{ void move(){ System.out.println("主角向前移动"); notifyObservers(); } }
main函数中代码
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(); } }
如果在被观察者之间有循环依赖的话,被观察者会触发它们之间进行循环调用,导致系统崩溃。在使用观察者模式是要特别注意这一点。
和发布订阅的区别