设计模式-观察者模式
定义:
在对象之间定义了一对多的依赖,这样一来,当一个对象改变状态,依赖它的对象会收到通知并自动更新。
更直观的说可以叫做发布订阅模式,发布者发布信息,订阅者获取信息,订阅了就能收到信息,没订阅就收不到。
两个角色:
- 被观察者:内部状态发生改变时,向观察者发出通知
- 观察者:收取被观察者的通知
应用场景:
- 基于消息发布订阅模式的应用
- 聊天软件
- 微博
- 在线购物等
- 在线游戏(MOBA游戏)
案例模拟:
被观察者抽象类:
public Subject(){
observers = new ArrayList<>();
}
/**
* 加关注
* @param o 关注的人
*/
public void addObserver(Observer o){
if (!observers.contains(o) && o != null){
observers.add(o);
}
}
/**
* 取消关注
* @param o
*/
public void removeObserver(Observer o){
if (observers.contains(o)){
observers.remove(o);
}
}
/**
* 消息通知
* @param o
*/
public void notifyAllObserver(Object o){
for (Observer observer : observers) {
observer.update(this,o);
}
}
public void notifyAllObserver(){
for (Observer observer : observers) {
observer.update(this, null);
}
}
观察者接口
public interface Observer {
/**
* 接受消息通知更新
* @param s 被观察者
* @param object 消息类型
*/
public void update(Subject s,Object object);
}
1. 商品降价通知
商品类
public class Product extends Subject{
//商品价格
private double price;
//商品名称
private String name;
public Product(String name) {
super();
this.name = name;
}
public double getPrice() {
return price;
}
//价格变动通知买家
public void setPrice(double price) {
this.price = price;
notifyAllObserver(new Double(price));
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
买家类:
public class Buyer implements Observer{
//接收商品降价通知
@Override
public void update(Subject s, Object object) {
if (object instanceof Double){
System.out.println("我降价了" +(Double)object);
}
}}
测试类:
Product niuzai = new Product("牛仔A");
Buyer b1 = new Buyer();
Buyer b2 = new Buyer();
Buyer b3 = new Buyer();
niuzai.addObserver(b1);
niuzai.addObserver(b2);
niuzai.addObserver(b3);
niuzai.setPrice(35.5);
输出结果:
商品价格发生变化时通知关注的卖家
,也就是观察者。
2.仿MOBA游戏英雄类
public class Hero extends Subject implements Observer{
//英雄位置
private Position position;
//名字
private String name;
public Position getPosition() {
return position;
}
public void setPosition(Position position) {
this.position = position;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Hero(Position position, String name) {
super();
this.position = position;
this.name = name;
}
//移动函数,模拟英雄进行移动
public void move(){
this.position.setX(this.position.getX() + 3);
this.position.setY(this.position.getY() + 2);
notifyAllObserver();
}
/**
* 模拟接收到其它英雄的位置
*/
@Override
public void update(Subject s, Object object) {
if (s instanceof Hero){
Hero hero = (Hero)s;
System.out.println(this.name + "发现了 " + hero.getName() + "在" +hero.getPosition().toString());
}
}}
测试类
Hero ganjiang = new Hero(new Position(4,5),"干将莫邪");
Hero hanxin = new Hero(new Position(-4,-5),"韩信");
ganjiang.addObserver(hanxin);
hanxin.addObserver(ganjiang);
int i = 0;
while (i++ < 100){
try {
//模拟延迟实现数据逐步输出
new Thread().sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
hanxin.move();
ganjiang.move();
}}
输出结果:
这种则是被观察者与观察者为一个类,即Hero即是观察者也是被观察者,这种类型还可以用到微博,聊天室等当中。
在Java当中也提供了被观察者抽象类Observable,与观察者接口Observer。