一、描述
定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。也称为发布-订阅模式。
角色:
1.抽象目标类:除自身业务逻辑外,包含增加、删除、唤醒观察者功能。
2.具体目标类:为那些在目标发生改变时需获取通知的对象定义一个更新接口。
2.抽象观察类:定义响应抽象方法。
3.具体观察类:继承抽象观察类,实现抽象方法。
类图:
二、优点
1.目标和观察者之间的耦合是最小的。一个目标所知道的仅仅是它有一系列的观察者,但是不知道这些观察者是哪些类,目标类只需要负责通知就可以了。
2.支持广播通信。通知被自动广播给所有已向该目标对象登记的有关对象。
三、缺点
1.意外的更新。因为一个观察者并不知道其他观察者的存在,它可能对改变目标的最终代价一无所知。
2.如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会话费很多的时间。
3.如果观察者和观察目标之间有循环依赖的话,观察目标会触发他们之间进行循环调用,可能导致系统崩溃。
四、适用场景
1.当对一个对象的改变需要同时改变其他对象,而不知道具体有多少对象有待改变
2.当一个对象必须通知其他对象,而它又不能假定其他对象是谁。
五、示例
以“交通灯亮,其他对象针对交通灯不同的颜色作出不同反应为例”。
1.抽象观察者类
public abstract class AbstractObserver {
/**
* 作出反应
*
* @param type
*/
abstract void update(Integer type);
}
2.具体观察者类,汽车、行人、自行车等
(1)汽车
public class CarObserver extends AbstractObserver {
@Override
void update(Integer type) {
System.out.print("我是轿车:");
if (Objects.equal(type, 1)) {
System.out.println("踩刹车,停车");
} else if (Objects.equal(type, 2)) {
System.out.println("开始行驶");
} else if (Objects.equal(type, 3)) {
System.out.println("缓慢行驶");
}
}
}
(2)行人
public class PedestriansObserver extends AbstractObserver {
@Override
void update(Integer type) {
System.out.print("我是行人:");
if (Objects.equal(type, 1)) {
System.out.println("原地站立");
} else if (Objects.equal(type, 2)) {
System.out.println("行走");
} else if (Objects.equal(type, 3)) {
System.out.println("行走,注意车辆");
}
}
}
(3)自行车
public class BikeObserver extends AbstractObserver {
@Override
void update(Integer type) {
System.out.print("我是自行车:");
if (Objects.equal(type, 1)) {
System.out.println("捏闸,停车");
} else if (Objects.equal(type, 2)) {
System.out.println("开始骑行");
} else if (Objects.equal(type, 3)) {
System.out.println("骑行,注意车辆");
}
}
}
3.抽象目标类
public abstract class AbstractSubject {
public List<AbstractObserver> observerList = new ArrayList<>();
public void addObservers(AbstractObserver observer) {
observerList.add(observer);
}
public void removeObserver(AbstractObserver observer) {
observerList.remove(observer);
}
/**
* 当前目标的行为
*
* @param type
*/
public abstract void doAction(Integer type);
}
4.具体目标类,交通灯类
public class TrafficFlightSubject extends AbstractSubject {
@Override
public void doAction(Integer type) {
if (Objects.equal(type, 1)) {
System.out.println("红灯亮");
} else if (Objects.equal(type, 2)) {
System.out.println("绿灯亮");
} else if (Objects.equal(type, 3)) {
System.out.println("黄灯亮");
}
for (AbstractObserver observer : observerList) {
observer.update(type);
}
}
}
5.测试类
public class Client {
public static void main(String[] args) {
TrafficFlightSubject subject = new TrafficFlightSubject();
CarObserver carObserver = new CarObserver();
subject.addObservers(carObserver);
PedestriansObserver pedestriansObserver = new PedestriansObserver();
subject.addObservers(pedestriansObserver);
BikeObserver bikeObserver = new BikeObserver();
subject.addObservers(bikeObserver);
//红灯
subject.doAction(1);
System.out.println();
//绿灯
subject.doAction(2);
System.out.println();
//黄灯
subject.doAction(3);
}
}
测试效果:
六、注意事项
观察者和中介者模式有些类似,但是不要弄混。二者的区别如下:
1.行为不同,观察者模式的目标类自身会有操作,之后通知观察者列表。中介者模式是直接通知对应的对象。
2.目的不同,观察者模式主要是一堆观察者观察目标类,当目标类有所操作之后,同时作出反应。中介者模式是一个对象通过中介通知另外一个对象。
3.目标群体不同,观察者模式中,目标类并不清楚观察者列表具体包含哪些对象;中介者模式的通知模式是清楚要通知哪些对象的。
推荐一篇解释二者对比比较透彻的文章:https://www.cdsy.xyz/computer/programme/design_pattern/230201/cd40017.html