项目实践之模板方法模式
2015-02-16 00:00
267 查看
摘要: 靡不有初, 鲜克有终。
这是一篇关于设计模式在项目中的实践运用,是一种设计思路,不是设计模式的理论讲解。
业务场景:公司为了提升用户转化率,往往会开展很多活动来吸引用户;比如什么抽奖活动、充值送红包活动、邀请好友活动等等,而且有时候活动内容都一样就形式不同。
例1:某活动必须先交易1元才能抽奖并且一个人只能抽2次、奖品iPad。。。。;需要展示中奖信息。
例2:某活动邀请1人送1次抽奖机会、但是参与过活动1并中奖的人抽不到奖;嘿嘿。
都需要判断活动是否开始或者结束。
如果让你做,你会怎么做(不是具体实现,主要是设计思路;怎么易于扩展,开展新活动更加迅速简单。)
实现1:每个活动封装一个接口、一个实现类;互不想干、老死不相往来。
不知道大家是这个想法吗?在我未进入现在这家公司时,就是这样做的;可能单纯的看也没什么不好的,但一个设计思路在项目中往往不是独立的个体,而且有时候在没有外部压力推动或者对自身要求不高(也可能没经验)的情况下,后来的编写者大部分都会遵循前一个的思路进行编码。
所以,既然是各写各的,大家互不影响;后来变成了:
服务端:每个活动新建interface,实现类,dao,bean,表,又因为是后台服务需要提供前台客户端调用,而公司服务端框架是RMI;每个method又要封装一个接口对外提供服务。
客户端:每次相应的也要重新调用新接口。
不知道如果是你来不断的重复这个编码过程,你会奔溃吗?
实现2:可能有的人想了,为什么不能对外只提供一个interface,不同的活动不同的实现;oop思想,所以有了下图。
我们再回到上面的例子,接下来是不是:
例1:判断活动时间、判断用户是否抽过2次奖、抽奖;
例2:判断活动时间、判断用户是否参加过活动1并中奖、抽奖。
如果严谨点,两个活动是不是都需要判断入参是否正确。聪明的你是不是已经发现判断活动时间、入参是公共方法,oop原则提取到父类;但我们不能更进一步吗?不管是判断抽奖2次,亦或活动2排斥活动1,还是其他;都是校验用户活动资格,我们又可以抽象一个方法出来了。结束了!其实我们还可以继续提取,两个活动的流程是相似的:第一步:都是活动校验,第二步:具体的活动处理。所以新鲜改造出炉的UML,看下面。
由抽象类实现doProcess方法,并控制行为,子类实现扩展可变的部分,这就是模板方法模式;很简单吧。(再次声明:这不是一篇讲解模板方法模式的blog,需要看模板方法模式的讲解度娘很多);代码片段:
ActivityService:
AbstractActivityService:
其他:在实际项目中,一个接口不可能定义所有的方法,也不能定义所有方法。即你不可能预知所有的活动形式,总有几个特殊逻辑,就比如猫和狗都是动物,但猫会爬树,狗不会;所以我们需要给猫增加一个爬树的能力;IActivityService1就是那个爬树的能力。
这样我们对外就可以仅提供一个接口IActivityService=new subClass()(取不同的子类实现);通过反射调用不同的方法(或者其他方式),做到仅关注具体业务逻辑的实现,不在循环重复流程化的开发。
总结:快过年了,也工作三年了、正好总结下。希望我的抛砖引玉能换来你更好的方案或者意见,如果对你还有那么一点帮助更开心了。由于本人水平有限,不足或错误之处希望大家能不吝赐教,请勿拍砖。也希望自己能不断坚持写下去。
ps:写这篇blog时,重新看了下“设计模式之禅”的模板方法模式(比起一年前看有种豁然开朗的感觉),最佳实践:父类不能调用子类的方法。按照我的理解有如下两种情况:
1、父类parent的doSomething里面调用son的test方法。这个我也是极度不认同的;按照我的想法,有父亲时不一定有儿子(不要纠结中文意思),父类怎么能调用子类的方法。
2、父类的声明子类的实现,client(不是父类,客户端调用的类)通过放射调用子类特有的方法。比如上面的爬树方法。这个按照我的理解是没问题的。
中文的意思太强大了,是不是我理解错作者的意思了,并没有指第二种情况仅指第一种?希望有人能解惑,谢谢!
这是一篇关于设计模式在项目中的实践运用,是一种设计思路,不是设计模式的理论讲解。
业务场景:公司为了提升用户转化率,往往会开展很多活动来吸引用户;比如什么抽奖活动、充值送红包活动、邀请好友活动等等,而且有时候活动内容都一样就形式不同。
例1:某活动必须先交易1元才能抽奖并且一个人只能抽2次、奖品iPad。。。。;需要展示中奖信息。
例2:某活动邀请1人送1次抽奖机会、但是参与过活动1并中奖的人抽不到奖;嘿嘿。
都需要判断活动是否开始或者结束。
如果让你做,你会怎么做(不是具体实现,主要是设计思路;怎么易于扩展,开展新活动更加迅速简单。)
实现1:每个活动封装一个接口、一个实现类;互不想干、老死不相往来。
不知道大家是这个想法吗?在我未进入现在这家公司时,就是这样做的;可能单纯的看也没什么不好的,但一个设计思路在项目中往往不是独立的个体,而且有时候在没有外部压力推动或者对自身要求不高(也可能没经验)的情况下,后来的编写者大部分都会遵循前一个的思路进行编码。
所以,既然是各写各的,大家互不影响;后来变成了:
服务端:每个活动新建interface,实现类,dao,bean,表,又因为是后台服务需要提供前台客户端调用,而公司服务端框架是RMI;每个method又要封装一个接口对外提供服务。
客户端:每次相应的也要重新调用新接口。
不知道如果是你来不断的重复这个编码过程,你会奔溃吗?
实现2:可能有的人想了,为什么不能对外只提供一个interface,不同的活动不同的实现;oop思想,所以有了下图。
我们再回到上面的例子,接下来是不是:
例1:判断活动时间、判断用户是否抽过2次奖、抽奖;
例2:判断活动时间、判断用户是否参加过活动1并中奖、抽奖。
如果严谨点,两个活动是不是都需要判断入参是否正确。聪明的你是不是已经发现判断活动时间、入参是公共方法,oop原则提取到父类;但我们不能更进一步吗?不管是判断抽奖2次,亦或活动2排斥活动1,还是其他;都是校验用户活动资格,我们又可以抽象一个方法出来了。结束了!其实我们还可以继续提取,两个活动的流程是相似的:第一步:都是活动校验,第二步:具体的活动处理。所以新鲜改造出炉的UML,看下面。
由抽象类实现doProcess方法,并控制行为,子类实现扩展可变的部分,这就是模板方法模式;很简单吧。(再次声明:这不是一篇讲解模板方法模式的blog,需要看模板方法模式的讲解度娘很多);代码片段:
ActivityService:
/** * 受理活动订单,一般分为如下步骤:<br> * 1、进行规则性校验,常规性校验有、”基础参数校验“、”活动时间校验“、”活动份额校验“、”活动资格校验“、 * 若个别活动还有特殊性规则校验,则自行添加。<br> * 2、预办理活动,进行实际的活动办理步骤,但不保存数据;先预办理活动保证活动实际受理成功率;若实际活动 * 办理失败,预办理活动已经修改的参数不进行实时回滚,另起JOB进行调度处理。<br> * 3、实际办理活动,实际为用户办理活动。<br> * * @param activityVo * <p>活动基础VO,具体活动的VO需继承此对象<br> * * @throws Exception * <p>调用活动受理接口,必须处理异常:一般为系统异常和自定义异常(BizException)<br> */ public ActivityRstVo doProcess(ActivityVo activityVo)throws Exception;
AbstractActivityService:
public ActivityRstVo doProcess(ActivityVo activityVo)throws Exception{ //校验活动基础规则 generalValidate(activityVo); //活动自定义规则 doActivityFilter(customValidate(activityVo),activityVo); //预办理活动 beforeActivity(activityVo); //实际办理活动 return doActivity(activityVo); } /** * 活动一般性规则校验 * * @param activityVo . * @throws Exception */ protected void generalValidate(ActivityVo activityVo)throws Exception{ boolean paramFlag = validateActivityParam(activityVo); if(!paramFlag){ throw new BizException(RespEnum.PARAMETERS_ERROR); } boolean activityTimeFlag = validateActivityTime(activityVo); if(!activityTimeFlag){ throw new BizException(RespEnum.ACT_NOT_EXIST_ERROR); } boolean costFlag = validateActivityCost(activityVo); if(!costFlag){ throw new BizException(RespEnum.ACT_AMT_ERROR); } boolean qualifiedFlag = validateActivityQualified(activityVo); if(!qualifiedFlag){ throw new BizException(RespEnum.ACT_IS_UNQUALIFICATION); } } /** * 校验用户活动资格,是否还能参加活动。 * * @param activityVo . * @return boolean:true 还能参加活动 false 不能参加此活动 * @throws Exception */ protected abstract boolean validateActivityQualified(ActivityVo activityVo)throws Exception; /** * 实际为用户办理活动,具体活动业务需要实现此方法 * * @param activityVo . * @throws Exception */ protected abstract ActivityRstVo doActivity(ActivityVo activityVo)throws Exception;
其他:在实际项目中,一个接口不可能定义所有的方法,也不能定义所有方法。即你不可能预知所有的活动形式,总有几个特殊逻辑,就比如猫和狗都是动物,但猫会爬树,狗不会;所以我们需要给猫增加一个爬树的能力;IActivityService1就是那个爬树的能力。
这样我们对外就可以仅提供一个接口IActivityService=new subClass()(取不同的子类实现);通过反射调用不同的方法(或者其他方式),做到仅关注具体业务逻辑的实现,不在循环重复流程化的开发。
总结:快过年了,也工作三年了、正好总结下。希望我的抛砖引玉能换来你更好的方案或者意见,如果对你还有那么一点帮助更开心了。由于本人水平有限,不足或错误之处希望大家能不吝赐教,请勿拍砖。也希望自己能不断坚持写下去。
ps:写这篇blog时,重新看了下“设计模式之禅”的模板方法模式(比起一年前看有种豁然开朗的感觉),最佳实践:父类不能调用子类的方法。按照我的理解有如下两种情况:
1、父类parent的doSomething里面调用son的test方法。这个我也是极度不认同的;按照我的想法,有父亲时不一定有儿子(不要纠结中文意思),父类怎么能调用子类的方法。
2、父类的声明子类的实现,client(不是父类,客户端调用的类)通过放射调用子类特有的方法。比如上面的爬树方法。这个按照我的理解是没问题的。
中文的意思太强大了,是不是我理解错作者的意思了,并没有指第二种情况仅指第一种?希望有人能解惑,谢谢!
相关文章推荐
- 【学习笔记javascript设计模式与开发实践(模板方法模式)----11】
- 模板方法模式实践
- 2016/5/6 thinkphp ①框架 ② 框架项目部署 ③MVC模式 ④控制器访问及路由解析 ⑤开发和生产模式 ⑥控制器和对应方法创建 ⑦视图模板文件创建 ⑧url地址大小写设置 ⑨空操作空控制器 ⑩项目分组
- JavaScript设计模式与开发实践 模板方法模式
- java与设计模式(六)-模板方法二基于项目开发
- 结合项目实例 回顾传统设计模式(八)模板方法模式
- 121 项目 030 笔记向 设计模式 模板方法模式
- 设计模式讲解与代码实践(二十三)——模板方法
- DH项目总结一(模板方法模式的使用)
- 结合项目实例 回顾传统设计模式(八)模板方法模式
- 模板方法模式实践1
- 模板方法模式实现探讨
- 第六个设计模式:模板方法
- 乐在其中设计模式(C#) - 模板方法模式(Template Method Pattern)
- 乐在其中设计模式(C#) - 模板方法模式(Template Method Pattern)
- 设计模式学习笔记(十六)——Template Method模板方法模式
- 模板方法模式(Template Method Pattern)
- 连接两个模板方法模式?
- 连接两个模板方法模式?
- 深入浅出Java模式设计之模板方法模式