观察者模式定义:
定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新
需求
利用企业给雇员加工资的形式来实现观察者模式,假设企业每隔半年的时间就会为所有员工加薪一次,每个员工能在第一时间知道加薪这一件事情, 具体表现为:
- 企业为可观察者,也就是主题
- 员工为观察者
- 企业会在第一时间通知所有员工加薪这件事情
- 员工会在第一时间收到消息并能做出反应
具体做法
- 设置一个主题接口,有添加、删除观察者的方法,有通知事件的方法
- 设置一个观察者接口,有更新的方法
- 自定义类实现主题接口
- 自定义类实现观察者接口
- 将观察者实现类加入到主题实现类中
- 主题更新时,将消息发送到所有的观察者实现类中
类图
代码实现
代码目录结构
Subject接口
package com.tmx.subject;
import com.tmx.observer.Observer;
public interface Subject {
void registerObserver(Observer observer);
void deleteObserver(Observer observer);
void notifyObserver();
}
Subject实现类 – SubjectImpl
package com.tmx.subject.impl;
import com.tmx.observer.Observer;
import com.tmx.subject.Subject;
import java.util.ArrayList;
import java.util.List;
public class SubjectImpl implements Subject {
private List<Observer> observers = new ArrayList<>(); //利用ArrayList来存储观察者对象
private Integer addSalary;
@Override
public void registerObserver(Observer observer) {
observers.add(observer);
System.out.println("添加"+ observer.getClass().getSimpleName() + "观察者成功");
}
@Override
public void deleteObserver(Observer observer) {
int i = observers.indexOf(observer);
observers.remove(i);
System.out.println(observer.getClass().getSimpleName() + "辞职成功");
}
@Override
public void notifyObserver() {
addSalary(500);
System.out.println("通知员工完毕!!");
}
private void addSalary(int i) {
for (Observer observer : observers) {
observer.update(i);
}
}
public void setAddSalary(Integer addSalary) {
this.addSalary = addSalary;
}
}
Observer接口
package com.tmx.observer;
public interface Observer {
void update(Integer money);
}
Observer实现类
tom
package com.tmx.observer.impl;
import com.tmx.observer.Observer;
public class Tom implements Observer {
private Integer salary;
public Tom(Integer salary) {
this.salary = salary;
}
@Override
public void update(Integer money) {
this.salary += money;
System.out.println(this.getClass().getSimpleName() + "已经收到加工资的通知" + this.salary);
}
}
Sun
package com.tmx.observer.impl;
import com.tmx.observer.Observer;
public class Sun implements Observer {
private Integer salary;
public Sun(Integer salary) {
this.salary = salary;
}
@Override
public void update(Integer money) {
this.salary += money;
System.out.println(this.getClass().getSimpleName() + "已经收到加工资的通知" + this.salary);
}
}
启动类
package com.tmx;
import com.tmx.observer.Observer;
import com.tmx.observer.impl.Sun;
import com.tmx.observer.impl.Tom;
import com.tmx.subject.Subject;
import com.tmx.subject.impl.SubjectImpl;
public class App
{
public static void main( String[] args )
{
Subject subject = new SubjectImpl();
Observer tom = new Tom(3000);
Observer sun = new Sun(3500);
subject.registerObserver(tom);
subject.registerObserver(sun);
subject.deleteObserver(tom);
subject.notifyObserver();
}
}
运行结果
后记
观察者模式的好处
- 降低了代码之间的耦合度
- 可以随时加入观察者和删除观察者,更加灵活
- 只要实现了Observer接口,就能加入主题对象中
用到的设计原则
- 为了交互对象之间的松耦合设计而努力
- 针对接口编程,不针对实现编程
一些疑问和解答
- 主题实现类中如何动态的获取到需要更新的数据?
- 在业务代码中,如何注册、删除一个观察者更合适?
解答:可以将主题的引用保存在观察者对象中,到时候直接调用删除观察者的方法
源码地址
观察者模式源码