Execute Around Pattern 环绕执行模式

135 阅读2分钟

目的

在执行同一类方法之前或/和之后需要做一些相同的操作。

例子代码

抗击疫情已经取得了阶段性胜利, 大家仍然要注意保护自己, 我们都需要勤洗手, 戴口罩。

每个人洗手的方式可能不一样, 这里我们需求是每个人完成洗手操作, 大概是这么写的:

public interface People {    void wasHands();}

这里面有二个人的话需要这么写:

public class Codog implements People {    @Override    public void wasHands() {        System.out.println("打开水龙头");        System.out.println("涂洗手液洗手");        System.out.println("关闭水龙头");    }}

加上:

public class Lanlan implements People {    @Override    public void wasHands() {        System.out.println("打开水龙头");        System.out.println("随便冲冲");        System.out.println("关闭水龙头");    }}

使用:

        People people = new Codog();        people.wasHands();        people = new Lanlan();        people.wasHands();

输出:

打开水龙头涂洗手液洗手关闭水龙头打开水龙头随便冲冲关闭水龙头

问题分析

很明显, 代码重复了。既然都需要打开和关闭水龙头, 那肯定要复用这部分代码, 不然新增多少人就需要重复多少次这种代码。

解决这种问题有非常多的办法, 这里我们使用一种相对简单改动比较快的代码。

环绕执行模式

public interface WashAction {    void wasHands(String name);}

模板:

public class WashTemplate {    public static void doWashing(String name, WashAction washAction) {        System.out.println("打开水龙头");        washAction.wasHands(name);        System.out.println("关闭水龙头");    }}

使用:

WashTemplate.doWashing("兰兰", (name) -> System.out.println(name + "随便冲冲"));

效果是一样的, 类图:

生产例子

触发定时任务的过程都是类似这种:

public class SelectActiveEmployeeCronJob implements SimpleJob {    @Override    public void execute(ShardingContext shardingContext) {        try {            LoggerUtil.info("executing job.." + "xxxjob");            jobLauncher.run(userJobConfig.selectActiveEmployeeJob(), defaultBatchJobFactory.createDefaultJobParam());        } catch (Exception e) {            LoggerUtil.error("execute job xxxjob failed", e);        }    }}

前后都需要打印日志, 并用 try-catch 包围.

可以改成类似操作:

public class JobStartTemplate {    @Autowired    private DefaultBatchJobFactory defaultBatchJobFactory;    public void executeJob(String jobName, ExecuteJobAction executeJobAction) {        LoggerUtil.info(jobName + " started:{}",new Date());        try {            executeJobAction.execute();        } catch (Exception e) {            LoggerUtil.error("execute job " + jobName + "failed", e);        }    }}

课后作业

1. 发送邮件都需要新连接邮件服务器, 发送具体的邮件, 关闭连接, 请用本设计模式实现

2. 除了正常 job, 还有某些特殊类型的 job, 比如开发打开才运行, 比如判断当前时间是否满足条件才运行, 写一个更通用的 ExecuteJobAction

3. JobStartTemplate 是需要是一个 static 方法 executeJob 还是使用依赖注入方式来调用 executeJob

![](https://mmbiz.qpic.cn/mmbiz_gif/mGswHATFXgEGKahyBD9TC859vbtSZ5EHjMxtTdO3O05Bj79eQY6hKj5acGUyQXIFCQo1QBBw2Vek2jicjGy1KiaQ/640?wx_fmt=gif&tp=webp&wxfrom=5&wx_lazy=1)

![](https://mmbiz.qpic.cn/mmbiz_gif/mGswHATFXgEGKahyBD9TC859vbtSZ5EHD1VwsltXx2sLAL1nQOwTIibeHwSJyHITgnk3jtoqUuKmEIA743jfTsg/640?wx_fmt=gif&tp=webp&wxfrom=5&wx_lazy=1)

长按识别二维码关注我们