Java设计模式之观察者模式
缘起
- 公司内部要做个培训功能,培训有考试,考试就要有试卷
- 在试卷完成答卷后,要计算试卷的得分,按照比例换算为培训的得分。
- 试卷不认识培训,试卷作答结果结束的时候,需要 通知 关注试卷结果的关注者们。
- 后期其他业务也需要用到试卷模块,所以,试卷不应该和任何的业务耦合,但要保证其他业务在关联试卷的时候,试卷的作答结果也可以通知到这个关注者。
开局
-回调函数,Java设计的时候就不支持函数,所以Java中想要函数的时候,一般用匿名内部类完成。此处,用接口来解决 要先有个 通知接口 来解耦,试卷模块只需要关联这个口,至于这个接口中做什么XXOO的事情,试卷不管。
/**
* Summary : 通知接口
*
* @Author Ray
* @Create 2020-08-13 9:50
*/
public interface Notifier<T> {
/**
* 通知
*
* @param t 通知内容
*/
void notifier(T t);
}
- 事件源
试卷与通知接口进行关联
此处的 notifiers 可以理解为广播容器。
当考试结果提交的时候,可以通过遍历关注者的集合,将结果推送给关注者们。
package com.sogdata.ideology.biz.service.exam;
import com.sogdata.ideology.biz.entity.exam.OnlineExamInstanceResult;
import com.sogdata.ideology.notifier.Notifier;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
/**
* Summary : 试卷实例的考试结果服务
*
* @Author Ray
* @Create 2020-08-04 23:09
*/
@Service
public class OnlineExamInstanceResultService {
/**
* 关注者集合
*/
public static ArrayList<Notifier<OnlineExamInstanceResult>> notifiers = new ArrayList<>();
/**
* 通知followers
*
* @param onlineExamInstanceResult 试卷实例的考试结果
*/
private void notifierAll(OnlineExamInstanceResult onlineExamInstanceResult) {
for (Notifier<OnlineExamInstanceResult> notifier : notifiers) {
notifier.notifier(onlineExamInstanceResult);
}
}
}
-观察者(关注者/跟随者)
将自己的回调函数注册到广播容器中,A/B/C三种写法都行,A/B是Java8的写法,C是8之前的写法,可以拍大腿盲测下Java8的函数是咋实现的。
package com.sogdata.ideology.biz.service.training;
import com.sogdata.ideology.biz.entity.exam.OnlineExamInstanceResult;
import com.sogdata.ideology.biz.service.exam.OnlineExamInstanceResultService;
import com.sogdata.ideology.notifier.Notifier;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import javax.validation.constraints.NotNull;
/**
* Summary : 培训参与人
*
* @Author Ray
* @Create 2020-08-11 18:09
*/
@Slf4j
@Service
public class OnlineTrainingParticipantService {
@PostConstruct
public void followExamInstanceResult() {
//A 写法
OnlineExamInstanceResultService.notifiers.add(this::updateExamInstanceResultIfExist);
//B 写法
OnlineExamInstanceResultService.notifiers.add(onlineExamInstanceResult -> {
});
//C 写法
OnlineExamInstanceResultService.notifiers.add(new Notifier<OnlineExamInstanceResult>() {
@Override
public void notifier(OnlineExamInstanceResult onlineExamInstanceResult) {
}
});
}
/**
* 将考试结果 异步写入 到的 对应的培训参与人
*
* @param onlineExamInstanceResult 培训结果实体
*/
@Async
void updateExamInstanceResultIfExist(@NotNull OnlineExamInstanceResult onlineExamInstanceResult) {
}
}
结尾
回忆一波,当时学这个模式的时候,Frank(我编程道路上的导师)说了一遍,我觉得我理解了,直到两年后,我才回过味来,为什么要用个notifier的接口,以及用这个的好处。设计模式很有意思,但要考虑是否有必要用,(就写个脚本,套个狗屁的设计模式,怎么快怎么来)。