责任链、Builder模式、模板模式、Listener模式乱炖

前言

面试中经常被你用过那些设计模式云云,具体参考《java设计模式之禅》
实际项目开发中应用了才是实战,此篇以告警提示需求为例将模式乱炖应用

缘起

常见系统中有错误或者如客服系统中客服不回复访客消息等要有短信、邮件、钉钉、微信公众号,写库等告警,当然通常有监控平台、调用链什么的平台,此外只叨叨代码层次上应用标题中的设计模式

责任链

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
/**
* 告警责任链
*
* @author hubo
* @since 2017-06-29 18:53
**/
public abstract class AlarmHandler {
protected final Logger LOGGER = LoggerFactory.getLogger(this.getClass());
protected AlarmHandler nextAlarmHandler;
protected AlarmHandler getNextAlarmHandler() {
return nextAlarmHandler;
}
/**
* 告警
*
* @param ruleTime 规则时间
*/
protected abstract void alarm(final long ruleTime, final AlarmEvent alarmInfo);
/**
* 钩子方法,是否告警
*/
protected abstract boolean isAlarm();
/**
* 模板方法: 告警业务
* 执行告警业务写库存及发微信
*
* @param alarmInfo 告警信息
*/
protected final void processAlarm(final AlarmEvent alarmInfo) {
AlarmManager alarmManager = new AlarmManager();
alarmManager.addListener(new WriteDBListenerImpl()); //记录到库
//alarmManager.addListener(new DingdingListenerImpl()); //钉钉发消息
//alarmManager.addListener(new SMSListenerImpl()); //发送短信提示
//alarmManager.addListener(new EmailListenerImpl()); //发送邮件提示
if (isAlarm()) {
alarmManager.addListener(new AlarmWechatListenerImpl());//微信告警
}
alarmManager.executeAlarm(alarmInfo);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
/**
* 客服链对象
* 分钟时间客服不回复访客消息则提示客服
*
* @author hubo
* @since 2017-06-29 18:57
**/
public class AlarmToCustomer extends AlarmHandler {
private AlarmToCustomer(Builder builder) {
this.nextAlarmHandler = builder.nextHandler;
}
@Override
protected boolean isAlarm() {
return true;
}
/**
* 告警业务操作
*
* @param ruleTime 规则时间
* @param alarmInfo
*/
public void alarm(final long ruleTime, final AlarmEvent alarmInfo) {
int count = alarmInfo.getCount();
if (ruleTime >= AlarmTypeEnum.TYPE1.getMinute() && count < 1) {//告警一次
alarmInfo.setCount(++count);
alarmInfo.setAlarmTypeEnum(AlarmTypeEnum.TYPE1);
super.processAlarm(alarmInfo);
} else {
if (getNextAlarmHandler() != null)
getNextAlarmHandler().alarm(ruleTime, alarmInfo);
}
}
public static class Builder {
private AlarmHandler nextHandler;
public Builder() {
}
public Builder(AlarmHandler nextHandler) {
this.nextHandler = nextHandler;
}
public Builder nextHandler(AlarmHandler nextHandler) {
this.nextHandler = nextHandler;
return this;
}
public AlarmToCustomer build() {
return new AlarmToCustomer(this);
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
/**
* Boss告警链
* 15分钟时间客服不回复访客消息通知Boss
*
* @author hubo
* @since 2017-06-29 18:57
**/
public class AlarmToBoss extends AlarmHandler {
private AlarmToBoss(Builder builder) {
this.nextAlarmHandler = builder.nextHandler;
}
@Override
protected boolean isAlarm() {
return true;
}
/**
* 告警业务操作
*
* @param ruleTime 规则时间
* @param alarmInfo
*/
public void alarm(final long ruleTime, final AlarmEvent alarmInfo) {
int count = alarmInfo.getCount();
if (ruleTime >= AlarmTypeEnum.TYPE2.getMinute() && count == 1) {
alarmInfo.setCount(++count);
alarmInfo.setAlarmTypeEnum(AlarmTypeEnum.TYPE2);
super.processAlarm(alarmInfo);
} else {
if (getNextAlarmHandler() != null)
getNextAlarmHandler().alarm(ruleTime, alarmInfo);
}
}
public static class Builder {
private AlarmHandler nextHandler;
public Builder() {
}
public Builder nextHandler(AlarmHandler nextHandler) {
this.nextHandler = nextHandler;
return this;
}
public AlarmToBoss build() {
return new AlarmToBoss(this);
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
/**
* 销毁任务对象链
* 超过30分钟时间客服不回复访客清除任务
*
* @author hubo
* @since 2017-06-29 18:57
**/
public class AlarmToDestroy extends AlarmHandler {
public AlarmToDestroy() {
}
@Override
protected boolean isAlarm() {
return false;
}
/**
* 告警业务操作
*
* @param ruleTime 规则时间
* @param alarmInfo 告警详情
*/
public void alarm(final long ruleTime, final AlarmEvent alarmInfo) {
if (ruleTime >= AlarmTypeEnum.TYPE3.getMinute()) {
AlarmBoxer.getInstance().remove(alarmInfo); //清除此条任务
alarmInfo.setAlarmTypeEnum(AlarmTypeEnum.TYPE3);
super.processAlarm(alarmInfo);
} else {
if (getNextAlarmHandler() != null)
getNextAlarmHandler().alarm(ruleTime, alarmInfo);
}
}
}

Listener模式

1
2
3
4
5
6
7
8
**
* 告警Listener
* @author hubo
* @since 2017-06-30 15:37
**/
public interface AlarmListener {
void alarm(AlarmEvent alarmInfo);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
* 告警记录到数据库
*
* @author hubo
* @since 2017-06-30 15:40
**/
public class WriteDBListenerImpl implements AlarmListener {
private AlarmLogMapper alarmLogMapper = SpringContextUtil.getBean("alarmLogMapper", AlarmLogMapper.class);
@Override
public void alarm(AlarmEvent alarmInfo) {
alarmLogMapper.insertSelective(alarmInfo); //插入数据库
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
/**
* 发微信公众号
*
* @author hubo
* @since 2017-06-30 15:40
**/
public class WechatListenerImpl implements AlarmListener {
@Override
public void alarm(AlarmEvent alarmInfo) {
System.out.print("发微信公众号");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class AlarmManager {
private Queue<AlarmListener> listeners = new ConcurrentLinkedQueue<>();
private ExecutorService executorService = Executors.newFixedThreadPool(2);
public void addListener(AlarmListener listener) {
listeners.add(listener);
}
/**
* 执行告警业务
*/
public void executeAlarm(final AlarmEvent alarmInfo) {
for (int i = 0, len = listeners.size(); i < len ; i++) {
executorService.submit(new Runnable() {
@Override
public void run() {
listeners.poll().alarm(alarmInfo);
}
});
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
/**
* @author hubo
* @since 2017-06-29 17:25
**/
public enum AlarmTypeEnum {
/** 客服5分钟无回复 */
TYPE1(1, 5),
/** 15分钟告警到Boss */
TYPE2(2, 15),
/** 30分钟无回复 */
TYPE3(3, 30);
private int type;
private int minute;
AlarmTypeEnum(int type, int minute) {
this.type = type;
this.minute = minute;
}
public int getType() {
return type;
}
public int getMinute() {
return minute;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**
* @author hubo
* @since 2017-06-29 17:22
**/
public class AlarmEvent {
/** 告警次数 */
private int count;
/** 类型 */
private AlarmTypeEnum alarmTypeEnum;
private AlarmEnum alarmEnum;
private Message message;
/** 访客发消息的时间 */
private long visitorSendMsgTime = System.currentTimeMillis();
//getter & setter

测试应用

1
2
3
4
5
6
7
8
9
10
11
12
13
public static void main(String[] args) {
//组合责任链
AlarmToDestroy destroy = new AlarmToDestroy();
AlarmToBoss boss = new AlarmToBoss.Builder().nextHandler(destroy).build();
AlarmToCustomer customer = new AlarmToCustomer.Builder().nextHandler(boss).build();
AlarmEvent alarmInfo = new AlarmEvent();
alarmInfo.setVisitorSendMsgTime(1500184270000);
customer.alarm(4, alarmInfo);
customer.alarm(20, alarmInfo);
customer.alarm(35, alarmInfo);
}