设计模式-责任连模式
常见设计模式分三大类:
- 创建模式:
工厂方法, 抽象工厂, 建造模式, 原型模式, 单例模式5种. - 结构模式:
适配器模式, 桥梁模式, 代理模式, 装饰模式, 门面模式5种. - 行为模式:
模板模式, 责任连模式, 迭代器模式, 观察者模式, 状态模式, 策略模式6种.
责任连模式
应用场景: 在业务线区分比较明显相对独立的复杂业务逻辑处理中,可以尝试使用责任连模式一环套一环.
意图: 避免请求发送者与接收者耦合在一起,让多个对象都有可能接收请求,将这些对象连接成一条链,并且沿着这条链传递请求,直到有对象处理它为止。
示例一:
- Handler.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
27package comdata.synch.model;
/**
* Created by xiehui1956(@)gmail.com on 16-12-8.
*/
public abstract class Handler {
/**
* 核心思想: 父类的引用指向子类的对象
*/
private Handler handler;
/**
* 具体角色实现自己的处理逻辑
*
* @param role
*/
public abstract void doWork(String role);
public Handler getHandler() {
return handler;
}
public void setHandler(Handler handler) {
this.handler = handler;
}
}
RoleConfig.java
1
2
3
4
5
6
7
8
9
10
11package comdata.synch.model;
/**
* Created by xiehui1956(@)gmail.com on 16-12-8.
*/
public class RoleConfig {
public static final String TEACHER = "teacher";
public static final String STUDENT = "student";
}StudentRequestHandler.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17package comdata.synch.model;
/**
* Created by xiehui1956(@)gmail.com on 16-12-8.
*/
public class StudentRequestHandler extends Handler {
@Override
public void doWork(String role) {
if (RoleConfig.STUDENT.equals(role)) {
System.out.println("在这里处理 * 同学 * 的请求");
} else if (RoleConfig.TEACHER.equals(role) && null != getHandler()) {
// 继续寻找处理者
getHandler().doWork(role);
}
}
}TeacherRequestHandler.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17package comdata.synch.model;
/**
* Created by xiehui1956(@)gmail.com on 16-12-8.
*/
public class TeacherRequestHandler extends Handler {
@Override
public void doWork(String role) {
if (RoleConfig.TEACHER.equals(role)) {
System.out.println("在这里处理 * 老师 * 的请求");
} else if (RoleConfig.STUDENT.equals(role) && null != getHandler()) {
// 继续寻找处理者
getHandler().doWork(role);
}
}
}AppTest.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
27package comdata.synch;
import comdata.synch.model.Handler;
import comdata.synch.model.RoleConfig;
import comdata.synch.model.StudentRequestHandler;
import comdata.synch.model.TeacherRequestHandler;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Created by xiehui1956(@)gmail.com on 16-12-7.
*/
public class AppTest {
private Logger LOGGER = LoggerFactory.getLogger(AppTest.class);
@Test
public void testSingleton() {
Handler teacher = new TeacherRequestHandler(), student = new StudentRequestHandler();
teacher.setHandler(student);
teacher.doWork(RoleConfig.TEACHER);
teacher.doWork(RoleConfig.STUDENT);
}
}
运行结果:1
2
3
4在这里处理 * 老师 * 的请求
在这里处理 * 同学 * 的请求
Process finished with exit code 0
实例,我是这么处理我们的业务逻辑
说明,这里由于牵着线上业务所以代码只能贴出来一部分,我尽量贴.
主入口, BaseHandler.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@Override
protected String processHandler(Request request) {
long startTime = System.currentTimeMillis();
BaseHandler paramCheck = new ParamCheckHandler(), pageDetail = new PageDetailHandler(), page = new PageHandler(), doProcess = new DoProcessHandler();
paramCheck.setDoWorker(pageDetail);
pageDetail.setDoWorker(page);
page.setDoWorker(doProcess);
String result = "";
CommonResult commonResult = new CommonResult();
// RequestValues values = new RequestValues(request);
try {
String requestURI = request.getRequestURI();
switch (requestURI) {
case "/bigdata":
paramCheck.handleRequest(request, commonResult);
// commonResult.setInfo(dataAction.getResultData(values));
break;
case "/bgsn":
SyncCassandraService cassandraService = new SyncCassandraService();
// 初始化数据
cassandraService.initSync();
// cassandraService.findOmsBrandInfo();
break;
case "/favicon.ico":
break;
default:
paramCheck.handleRequest(request, commonResult);
break;
}
} catch (NumberFormatException e) { //数字格式错误
commonResult.setCodeAndMessage(ApiMessage.SHU_ZI_GE_SHI_ERROR.code, ApiMessage.SHU_ZI_GE_SHI_ERROR.message);
logService.printErrorLog(logService.getStackTrace(e));
} catch (Exception e) {
commonResult.setCodeAndMessage(ApiMessage.ERROR.code, ApiMessage.ERROR.message);
logService.printErrorLog(logService.getStackTrace(e));
} finally {
long ms = System.currentTimeMillis() - startTime;
if (null != commonResult.getInfo())
addRTLog(commonResult.getInfo().toString(), ms);
}
return responseResult(commonResult);
}BaseHandler.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
29package com.redstar.data.common.base;
import com.redstar.data.api.dto.CommonResult;
import org.eclipse.jetty.server.Request;
import java.sql.SQLException;
/**
* Created by xiehui1956(@)gmail.com on 16-11-4.
*/
public abstract class BaseHandler {
/**
* 后续责任对象
*/
protected BaseHandler doWorker;
/**
* 流程处理
*
* @param request
* @return
*/
public abstract CommonResult handleRequest(Request request, CommonResult commonResult) throws SQLException;
public void setDoWorker(BaseHandler doWorker) {
this.doWorker = doWorker;
}
}ParamCheckHandler.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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132package com.redstar.data.api.service.handler;
import com.redstar.data.api.dto.CommonResult;
import com.redstar.data.api.helper.BigDataApiHelper;
import com.redstar.data.api.helper.WebAppConfig;
import com.redstar.data.api.model.RequestParam;
import com.redstar.data.common.base.BaseHandler;
import com.redstar.data.common.base.BaseLogService;
import com.redstar.data.common.exception.ApiMessage;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.util.StringUtil;
import java.sql.SQLException;
import java.util.Set;
/**
* Created by xiehui1956(@)gmail.com on 16-11-4.
* 参数检测
*/
public class ParamCheckHandler extends BaseHandler {
private BaseLogService baseLogService = BaseLogService.getInstance();
/**
* 参数验证
*
* @param request
* @return
*/
@Override
public CommonResult handleRequest(Request request, CommonResult commonResult) throws SQLException {
// 初始化参数
RequestParam.newInstance().initParam(request);
// 验证必传参数
if (paramIsBlank(RequestParam.newInstance().fields, RequestParam.newInstance().owner, RequestParam.newInstance().operation, RequestParam.newInstance().datatypes, RequestParam.newInstance().ids)) {
commonResult.setCodeAndMessage(ApiMessage.CAN_SHU_ERROR.code, ApiMessage.CAN_SHU_ERROR.message);
baseLogService.printWarnLog(String.format("必传参数不能为空:%s", RequestParam.newInstance().toString()));
return commonResult;
}
// ids长度验证, 防止
if (WebAppConfig.App.requestIdsMaxLength < RequestParam.newInstance().idsSet.size()) {
commonResult.setCodeAndMessage(ApiMessage.CAN_SHU_ERROR.code, ApiMessage.CAN_SHU_ERROR.message);
baseLogService.printWarnLog("ids长度过长,最大支持500个");
return commonResult;
}
// 验证参数合法性 - operation
if (!WebAppConfig.App.checkOperation(RequestParam.newInstance().operation)) {
commonResult.setCodeAndMessage(ApiMessage.CAN_SHU_ERROR.code, ApiMessage.CAN_SHU_ERROR.message);
baseLogService.printWarnLog("业务放标识不合法");
return commonResult;
}
// dataType验证, 此处区分大小写
if (!RequestParam.newInstance().datatypesSet.contains(BigDataApiHelper.Datatypes.HISTORY) &&
!RequestParam.newInstance().datatypesSet.contains(BigDataApiHelper.Datatypes.NOW)) {
commonResult.setCodeAndMessage(ApiMessage.CAN_SHU_ERROR.code, ApiMessage.CAN_SHU_ERROR.message);
baseLogService.printWarnLog("dataType参数不对");
return commonResult;
}
// 验证业务方fields
if (!checkRequestFields()) {
commonResult.setCodeAndMessage(ApiMessage.CAN_SHU_ERROR.code, ApiMessage.CAN_SHU_ERROR.message);
baseLogService.printWarnLog("fields参数不对");
return commonResult;
}
// fields中id必传
if (!RequestParam.newInstance().fieldsSet.contains("id")) {
RequestParam.newInstance().fieldsSet.add("id");
RequestParam.newInstance().queryFieldsSet.add("id");
BaseLogService.getInstance().printWarnLog("注意:id属性为请求必传字段请求未携带该字段,系统自动添加.");
}
commonResult.setOwner(RequestParam.newInstance().owner);
commonResult.setOperation(RequestParam.newInstance().operation);
return doWorker.handleRequest(request, commonResult);
}
/**
* 验证请求属性是否合法
*
* @return false:不合法; true:合法
*/
public boolean checkRequestFields() {
if (RequestParam.newInstance().fieldsSet.size() > WebAppConfig.App.requestFieldsMaxLength) {
baseLogService.printWarnLog(String.format("fields字段长度过长, 限制长度:%d ; 实际长度:%d, 实际内容:%s",
WebAppConfig.App.requestFieldsMaxLength,
RequestParam.newInstance().fieldsSet.size(),
RequestParam.newInstance().fields));
return false;
}
StringBuilder errorField = new StringBuilder();
Set<String> fieldsByOperation = WebAppConfig.App.getFieldsByOperation(RequestParam.newInstance().operation);
for (String field : RequestParam.newInstance().fieldsSet) {
if (!fieldsByOperation.contains(field))
errorField.append(field).append(",");
}
if (errorField.length() > 0) {
errorField = errorField.deleteCharAt(errorField.length() - 1);
baseLogService.printWarnLog(String.format("请求的fields字段中含有系统中没有配置的字段,请求owner为:%s ; 请求operation为:%s ; 非法fields为:%s ",
RequestParam.newInstance().owner,
RequestParam.newInstance().operation,
errorField.toString()));
}
return true;
}
/**
* 检测必传参数是否为空
*
* @param fields 需要返回哪些值
* @param owner 使用方名称
* @param operation 调用接口业务类型
* @param datatypes 需要返回的数据种类,数据种类包含两种(history/now)
* @param ids 一次需要返回多个id的结果信息,用逗号隔开
* @return
*/
public boolean paramIsBlank(String fields, String owner, String operation, String datatypes, String ids) {
return StringUtil.isBlank(fields) ||
StringUtil.isBlank(owner) ||
StringUtil.isBlank(operation) ||
StringUtil.isBlank(datatypes) ||
StringUtil.isBlank(ids);
}
}CommonResult.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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120package com.redstar.data.api.dto;
import com.redstar.data.common.exception.ApiMessage;
import java.io.Serializable;
/**
* Created by xiehui1956(@)gmail.com on 16-9-8.
* 通用结果
*/
public class CommonResult implements Serializable {
/**
* 状态码
*/
private int code = ApiMessage.SUCCESS.code;
/**
* 操作者
*/
private String owner = null;
/**
* 业务类型
*/
private String operation = null;
/**
* 描述
*/
private String error = ApiMessage.SUCCESS.message;
/**
* 时间戳
*/
private Long ts = System.currentTimeMillis();
/**
* 响应数据
*/
private Object info = null;
public CommonResult() {
}
public void setCodeAndMessage(int code, String error) {
this.code = code;
this.error = error;
}
public CommonResult(int code, String error, String owner, String operation, Object info) {
this.code = code;
this.error = error;
this.owner = owner;
this.operation = operation;
this.info = info;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getOwner() {
return owner;
}
public void setOwner(String owner) {
this.owner = owner;
}
public String getOperation() {
return operation;
}
public void setOperation(String operation) {
this.operation = operation;
}
public String getError() {
return error;
}
public void setError(String error) {
this.error = error;
}
public Long getTs() {
return ts;
}
public void setTs(Long ts) {
this.ts = ts;
}
public Object getInfo() {
return info;
}
public CommonResult setInfo(Object info) {
this.info = info;
return this;
}
@Override
public String toString() {
return "CommonResult{" +
"code=" + code +
", owner='" + owner + '\'' +
", operation='" + operation + '\'' +
", error='" + error + '\'' +
", ts=" + ts +
", info=" + info +
'}';
}
}ApiMessage.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
51package com.redstar.data.common.exception;
/**
* Created by xiehui1956(@)gmail.com on 16-8-9.
*/
public enum ApiMessage {
SUCCESS(ApiStatusCode.SUCCESS, "成功"),
FAIL(ApiStatusCode.FAIL, "失败"),
CAN_SHU_ERROR(ApiStatusCode.CAN_SHU_ERROR, "参数错误"),
ZI_DUAN_WEI_KONG(ApiStatusCode.ZI_DUAN_WEI_KONG, "非空字段为空"),
SHU_ZI_GE_SHI_ERROR(ApiStatusCode.SHU_ZI_GE_SHI_ERROR, "数字格式错误"),
YAN_ZHENG_ERROR(ApiStatusCode.FAIL_JIAO_YAN_ERROR, "校验错误"),
ERROR(ApiStatusCode.FAIL_SYSTEM_ERROR, "server error call admin"),
GE_SHI_ERROR(ApiStatusCode.FAIL_GE_SHI_ERROR, "请求格式错误"),
WU_QUAN_FANG_WEN(ApiStatusCode.FAIL_WU_QUAN_FANG_WEN, "无权访问该资源"),
FAIL_NEED_LOGIN(ApiStatusCode.FAIL_NEED_LOGIN, "需要登录访问"),
FAIL_ZI_YUAN_BU_CUN_ZAI(ApiStatusCode.FAIL_ZI_YUAN_BU_CUN_ZAI, "资源不存在"),
WEI_SHOU_QUAN(ApiStatusCode.FAIL_WEI_SHOU_QUAN, "未授权");
public int code;
public String message;
ApiMessage(int code, String message) {
this.code = code;
this.message = message;
}
public String getMessage(int code) {
for (ApiMessage apiMessage : ApiMessage.values()) {
if (code == apiMessage.getCode())
return message;
}
return "";
}
private int getCode() {
return code;
}
private void setCode(int code) {
this.code = code;
}
private void setMessage(String message) {
this.message = message;
}
}BaseLogService.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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195package com.redstar.data.common.base;
import com.google.common.collect.Queues;
import com.redstar.data.api.helper.PropertiesConfig;
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* Created by xiehui1956(@)gmail.com on 16-11-8.
* 日志操作
*/
public class BaseLogService {
/**
* 创建线程数
*/
private final static int rt_logTask = 30;
/**
* 日志队列
*/
private ArrayBlockingQueue<String> blockingServiceQueue, blockingInfoQueue, blockingWarnQueue, blockingErrorQueue;
private static BaseLogService logService;
/**
* 业务相关, 主要用于日志分析等作用
*/
private Logger log_service = Logger.getLogger("RS_SERVICE");
/**
* 普通记录,用于记录系统日志
*/
private Logger log_info = Logger.getLogger("RS_INFO");
/**
* 用于记录系统警告
*/
private Logger log_warn = Logger.getLogger("RS_WARN");
/**
* 用于记录系统错误
*/
private Logger log_error = Logger.getLogger("RS_ERROR");
public static BaseLogService getInstance() {
if (null == logService)
logService = new BaseLogService();
return logService;
}
private BaseLogService() {
// 加载日志配置
PropertyConfigurator.configure(PropertiesConfig.getConfigPath(PropertiesConfig.LOG4J));
//日志打印
this.blockingServiceQueue = Queues.newArrayBlockingQueue(15000);
this.blockingInfoQueue = Queues.newArrayBlockingQueue(15000);
this.blockingWarnQueue = Queues.newArrayBlockingQueue(15000);
this.blockingErrorQueue = Queues.newArrayBlockingQueue(15000);
ExecutorService executors = Executors.newFixedThreadPool(30);
for (int i = 0; i < rt_logTask; i++) {
// service
executors.execute(new Runnable() {
@Override
public void run() {
String service = null;
while (true) {
try {
service = blockingServiceQueue.take();
} catch (InterruptedException e) {
service = null;
}
if (service == null) continue;
log_service.info(service);
service = null;
}
}
});
// info
executors.execute(new Runnable() {
@Override
public void run() {
String info = null;
while (true) {
try {
info = blockingInfoQueue.take();
} catch (InterruptedException e) {
info = null;
}
if (info == null) continue;
log_info.info(info);
info = null;
}
}
});
// warn
executors.execute(new Runnable() {
@Override
public void run() {
String warn = null;
while (true) {
try {
warn = blockingWarnQueue.take();
} catch (InterruptedException e) {
warn = null;
}
if (warn == null) continue;
log_warn.warn(warn);
warn = null;
}
}
});
// error
executors.execute(new Runnable() {
@Override
public void run() {
String error = null;
while (true) {
try {
error = blockingErrorQueue.take();
} catch (InterruptedException e) {
error = null;
}
if (error == null) continue;
log_error.error(error);
error = null;
}
}
});
}
}
/**
* 打印日志
*
* @param clazz
* @param log
*/
public void printServiceLog(Class clazz, String log) {
StringBuffer logInfo = new StringBuffer();
logInfo.append(" ").append(clazz.toString()).append(" ").append(log);
blockingServiceQueue.offer(logInfo.toString());
}
/**
* 打印info日志
*
* @param log
*/
public void printInfoLog(String log) {
blockingInfoQueue.offer(log);
}
/**
* 打印warn日志
*
* @param log
*/
public void printWarnLog(String log) {
blockingWarnQueue.offer(log);
}
/**
* 打印error日志
*
* @param log
*/
public void printErrorLog(String log) {
blockingErrorQueue.offer(log);
}
/**
* 异常信息
*
* @param ex
* @return
*/
public String getStackTrace(Exception ex) {
String err = "";
StackTraceElement[] emArr = ex.getStackTrace();
err += "\n" + ex.toString() + "\n";
for (int i = 0; i < emArr.length; i++) {
err += emArr[i].toString() + "\n";
}
return err;
}
}
说明: 这些代码应该可以说明问题了. 责任连的设置在第一个方法中”BaseHandler paramCheck = new ParamCheckHandler()”这里.
以上.