观察者模式


  有两组实体对象,一组是观察者,一组是被观察者。Concretesubject是被观察者,ConcreteObserver是观察者。所有的观察者,都实现了Observer接口;所有的被观察者,都继承自Subject抽象类。
听着有点懵逼,直接上代码

定义一个观察者接口

//观察者
public interface Observer {
	public void update();
}

定义被观察者抽象类

//被观察者
abstract 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方法。分别对观察者有不同的处理方法。

 

创建主角类,他是被观察的对象,主教类做出操作,这时候就调用notifyObServers()方法来进行通知观察者,观察者分别调用自己的update()方法。

//被观察者
public class Hero extends Subject{
	
	void move() {
		System.out.println("主角向前移动");
		//触发操作,遍历通知观察者
		notifyObservers();
	}

}

以下是测试类

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();
    }
}

 结果:

主角向前移动
怪物对主角进行攻击!
陷阱 困住主角!
宝物 为主角加血!

我们可以看到只要hero触发move,其他观察者对象都做出了反应。

什么时候用观察者模式呢?

 当一个对象的改变需要同时改变其它对象,并且它不知道具体有多少对象有待改变的时候,应该考虑使用观察者模式。

   而使用观察者模式的动机在于:将一个系统分割成一系列相互协作的类有一个很不好的副作用,就是需要维护相关对象间的一致性,我们不希望为了维持一致性而使各类紧密耦合,这样会给维护、扩展和重用都带来不便,而观察者模式所做的工作就是在解除耦合

应用实例:

  • 手机丢了,委托别人给其他人发消息通知
  • 通知老师/老板来了
  • 拍卖,拍卖师观察最高标价,然后通知给其它竞价者竞价
  • 在一个目录下建立一个文件,会同时通知目录管理器增加目录,并通知磁盘减少空间,文件是被观察者,目录管理器和磁盘管理器是观察者
  • 猫叫了一声,吓着了老鼠,也惊到了主人,猫是被观察者,老鼠和人是观察者。

注意事项:

  • 避免循环引用
  • 如果顺序执行,某一观察者错误会导致系统卡壳,一般采用异步方式。

       https://zhuanlan.zhihu.com/p/158537313

       https://www.cnblogs.com/adamjwh/p/10913660.html

posted @ 2022-03-22 10:57  程序员hg  阅读(29)  评论(0编辑  收藏  举报