面试的时候别再说你不会设计模式了
前言
最近在设计一个对某个中间件的测试方案,这个测试方案需要包含不同的测试逻辑,但相同的是需要对各个环节进行记录;比如统计耗时、调用通知API等相同的逻辑。
如果每个测试都单独写这些逻辑那无疑是做了许多重复工作了。
基于以上的特征很容易能想到模板方法这个设计模式。
这是一种有上层定义框架,下层提供不同实现的设计模式。
比如装修房子的时候业主可以按照自己的喜好对不同的房间进行装修,但是整体的户型图不能做修改,比如承重墙是肯定不能打的。
而这些固定好的条条框框就是上层框架给的约束,下层不同的实现就有业主自己决定;所以对于整栋楼来说框架都是固定好的,让业主在有限的范围内自由发挥也方便物业的管理。具体实现
以我这个案例的背景为例,首先需要定义出上层框架:Java
Event接口:publicinterfaceEvent{新增一个任务voidaddJob();单个任务执行完毕paramjobName任务名称paramfinishCost任务完成耗时voidfinishOne(StringjobName,StringfinishCost);单个任务执行异常paramjobDefine任务parame异常voidoneException(AbstractJobDefinejobDefine,Exceptione);所有任务执行完毕voidfinishAll();}publicvoidstart(){event。addJob();try{CompletableFuture。runAsync((){StopWatchwatchnewStopWatch();try{watch。start(jobName);不同的子业务实现run(client);}catch(Exceptione){event。oneException(this,e);}finally{watch。stop();event。finishOne(jobName,StrUtil。format(cost:{}s,watch。getTotalTimeSeconds()));}},TestCase。EXECUTOR)。get(timeout,TimeUnit。SECONDS);}catch(Exceptione){event。oneException(this,e);}}RunbusycodeparamclientthrowsExceptionepublicabstractvoidrun(Clientclient)throwsException;
其中最核心的就是run函数,它是一个抽象函数,具体实现交由子类完成;这样不同的测试用例之间也互不干扰,同时整体的流程完全相同:记录任务数量统计耗时异常记录
等流程。
接下来看看如何使用:AbstractJobDefinejob1newTest1(event,测试1,client,10);CompletableFutureVoidc1CompletableFuture。runAsync(job1::start,EXECUTOR);AbstractJobDefinejob2newTest2(event,测试2,client,10);CompletableFutureVoidc2CompletableFuture。runAsync(job2::start,EXECUTOR);AbstractJobDefinejob3newTest3(event,测试3,client,20);CompletableFutureVoidc3CompletableFuture。runAsync(job3::start,EXECUTOR);CompletableFutureVoidallCompletableFuture。allOf(c1,c2,c3);all。whenComplete((,){event。finishAll();client。close();})。get();
显而易见Test13都继承了AbstractJobDefine同时实现了其中的run函数,使用的时候只需要创建不同的实例等待他们都执行完成即可。
以前在Java中也有不同的应用:
https:crossoverjie。top20190301algorithmconsistenthash?highlightE6A8A1E69DBFE696B9E6B395E6A8A1E69DBFE696B9E6B395Go
同样的示例用Go自然也可以实现:
funcTestJobDefinestart(ttesting。T){event:NewEvent()j1:JobDefine{Event:event,Run:run1{},JobName:job1,Param1:p1,Param2:p2,}j2:JobDefine{Event:event,Run:run2{},JobName:job2,Param1:p11,Param2:p22,}j1。Start()j2。Start()for,ch:rangeevent。GetChan(){ch}log。Println(finishall)}func(rrun2)Run(param1,param2string)error{log。Printf(run3param1:s,param2:s,param1,param2)time。Sleep(time。Second3)returnerrors。New(testerr)}func(rrun1)Run(param1,param2string)error{log。Printf(run1param1:s,param2:s,param1,param2)returnnil}
使用起来也与Java类似,创建不同的实例;最后等待所有的任务执行完毕。总结
设计模式往往是对某些共性能力的抽象,但也没有一个设计模式可以适用于所有的场景;需要对不同的需求选择不同的设计模式。
至于在工作中如何进行正确的选择,那就需要自己日常的积累了;比如多去了解不同的设计模式对于的场景,或者多去阅读优秀的代码,Java中的InputStreamReaderWriter这类IO相关的类都有具体的应用。