Fork me on GitHub

设计模式——模板方法的应用

模板方法

模板方法

很多情况下代码中的业务都可以抽象出一个模板去解决,这时候经常需要用到模板方法。大家经常接触到的是一些业务方法的抽象模板,比如在计算优惠券的流程当中总是有一定的步骤:

(1)先计算该商品是否可以拥有优惠券信息

(2)再为该商品绑定优惠券信息

(3)最后回调或者通知向下的流程

今天要记录的是一个通用服务层的模板方法,包含了前置校验、后置处理(是有点像拦截器= =)、finally操作。

业务processor

  1. 可以定义一个domainProcessor去代表业务操作的processor接口,这个接口可以承接泛型。
1
2
3
4
5
6
7
8
9
public interface DomainProcessor<T> {

/**
* 处理业务的方法 返回值现在是void的 也可以自己定义一个通用的类似于上下文的返回值
*
* @param context
*/
void process(T context);
}

这里承接的泛型context是一个上下文的概念,指的是在一个业务处理processor中的上下文信息,其中可以有计算的参数,计算的结果和一些中间信息。

  1. 做一个抽象类,去将其中的前置操作、biz操作、后置操作、finally操作定义出来。
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
public abstract class AbstractProcessor<T> implements DomainProcessor<T> {

/**
* 前置处理 主要做一些校验逻辑 编排的时候放在前边
*
* @param context
* @return
*/
protected boolean preHandle(T context){
return true;
}

/**
* 业务处理 这个是抽象方法 子类去实现具体的逻辑
* @param context
*/
protected abstract void bizHandle(T context);

/**
* 后置处理
*
* @param context
*/
protected void postHandle(T context) {
}

/**
* last 操作
* @param context
*/
protected void finallyHandle(T context) {
}

/**
* 异常处理
*
* @param context
* @param e
*/
protected void exceptionHandle(T context, Exception e) {
// TODO 打印error或者warn级别日志
throw new BizException(e.getMessage(), e);
}

@Override
public void process(T context) {
/**
* 编排流程
*/
try {
if (!preHandle(context)) {
// log.warn("处理器前置处理失败,退出。context:{}", context);
return;
}
// 业务方法
bizHandle(context);
// 后置操作
postHandle(context);
} catch (Exception e) {
exceptionHandle(context, e);
} finally {
finallyHandle(context);
}
}

}

可以看到,这里定义了前置操作,这里可以去对biz要用的参数进行一个校验或者一些前置操作,同时将biz定义为了抽象方法,意图在为了让子类去继承时一定要去实现bizHandle这个方法。而exceptionHandle和finallyHandle方法则定义了异常的处理和最终要做的(比如线程快照的清除)。而整个process方法其实就是整个处理器的入口,即对这整个流程的一个编排。

可以看一个这个模板processor的的具体实现和测试类:

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
public class AbstractProcessorTest {

private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();

public static void main(String[] args) {
// TODO test
TestContext testContext = new TestContext();
contextHolder.set("aaa");
TestProcessor testProcessor = new TestProcessor();
// 调用process的编排
testProcessor.process(testContext);

TestContext exContext = new TestContext();
// test bizHandle
testProcessor.process(exContext);
}

private static class TestProcessor extends AbstractProcessor<TestContext> {
@Override
protected boolean preHandle(TestContext context) {
// 前置的一个check或者一个前置操作
String s = contextHolder.get();
if (s == null) {
throw new RuntimeException("holder中字符串为空");
}

context.setMessage(s);
return true;
}

@Override
protected void postHandle(TestContext context) {
context.setPostStr("post");
System.out.println("processor 结果是:"+ context.isResult());
}

@Override
protected void finallyHandle(TestContext context) {
if (context.isResult()) {
contextHolder.remove();
}
}

@Override
protected void bizHandle(TestContext context) {
context.setResult(context.getMessage().length()>0);
}
}
}

总结

这个模板可以作为之后一个处理器的抽象模板,能让代码逻辑很清晰的展现出来,也能解耦了各个处理模块,这里可以总结下。

-------------本文结束感谢您的阅读-------------

本文标题:设计模式——模板方法的应用

文章作者:夸克

发布时间:2019年02月01日 - 16:02

最后更新:2022年07月01日 - 05:07

原始链接:https://zhanglijun1217.github.io/2019/02/01/设计模式——模板方法的应用/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。