继续设计模式~ 模版方法模式
老套路,先看下定义:定义了一个算法的骨架,而将一些步骤延迟到子类中,模版方法使得子类可以在不改变算法结构的情况下,重新定义算法的步骤。
简单看下定义,模版方法定义了一个算法的步骤,并且允许子类为一个或多个步骤提供实现。定义还算清晰,下面来个例子展示下本公司的上班情况(纯属娱乐,如有雷同,请对号入座)。简单描述一下:本公司有程序猿、测试、HR、项目经理等人,下面使用模版方法模式,记录下所有人员的上班情况:
首先来个超类,超类中定义了一个workOneDay方法,设置为作为算法的骨架:
package com.zhy.pattern.template; public abstract class Worker { protected String name; public Worker(String name) { this.name = name; } /** * 记录一天的工作 */ public final void workOneDay() { System.out.println("-----------------work start ---------------"); enterCompany(); computerOn(); work(); computerOff(); exitCompany(); System.out.println("-----------------work end ---------------"); } /** * 工作 */ public abstract void work(); /** * 关闭电脑 */ private void computerOff() { System.out.println(name + "关闭电脑"); } /** * 打开电脑 */ private void computerOn() { System.out.println(name + "打开电脑"); } /** * 进入公司 */ public void enterCompany() { System.out.println(name + "进入公司"); } /** * 离开公司 */ public void exitCompany() { System.out.println(name + "离开公司"); } }
定义了一个上班(算法)的骨架,包含以下步骤:
a、进入公司
b、打开电脑
c、上班情况
d、关闭电脑
e、离开公司
可以看到,a、b、d、e我们在超类中已经实现,子类仅实现work这个抽象方法,记录每天的上班情况。下面各类屌丝入场:
程序猿:
package com.zhy.pattern.template; public class ITWorker extends Worker { public ITWorker(String name) { super(name); } @Override public void work() { System.out.println(name + "写程序-测bug-fix bug"); } }
HR:
package com.zhy.pattern.template; public class HRWorker extends Worker { public HRWorker(String name) { super(name); } @Override public void work() { System.out.println(name + "看简历-打电话-接电话"); } }
测试人员:
package com.zhy.pattern.template; public class QAWorker extends Worker { public QAWorker(String name) { super(name); } @Override public void work() { System.out.println(name + "写测试用例-提交bug-写测试用例"); } }
项目经理:
package com.zhy.pattern.template; public class ManagerWorker extends Worker { public ManagerWorker(String name) { super(name); } @Override public void work() { System.out.println(name + "打dota..."); } }
下面我们测试下:
package com.zhy.pattern.template; public class Test { public static void main(String[] args) { Worker it1 = new ITWorker("鸿洋"); it1.workOneDay(); Worker it2 = new ITWorker("老张"); it2.workOneDay(); Worker hr = new HRWorker("迪迪"); hr.workOneDay(); Worker qa = new QAWorker("老李"); qa.workOneDay(); Worker pm = new ManagerWorker("坑货"); pm.workOneDay(); } }
输出结果:
-----------------work start --------------- 鸿洋进入公司 鸿洋打开电脑 鸿洋写程序-测bug-fix bug 鸿洋关闭电脑 鸿洋离开公司 -----------------work end --------------- -----------------work start --------------- 迪迪进入公司 迪迪打开电脑 迪迪看简历-打电话-接电话 迪迪关闭电脑 迪迪离开公司 -----------------work end --------------- -----------------work start --------------- 老李进入公司 老李打开电脑 老李写测试用例-提交bug-写测试用例 老李关闭电脑 老李离开公司 -----------------work end --------------- -----------------work start --------------- 坑货进入公司 坑货打开电脑 坑货打dota... 坑货关闭电脑 坑货离开公司 -----------------work end ---------------
好了,恭喜你,又学会一个设计模式,模版方法模式。
下面看下模版方法模式类图,和我们程序的类图:
模版方式里面也可以可选的设置钩子,比如现在希望记录程序员离开公司的时间,我们就可以在超类中添加一个钩子:
public boolean isNeedPrintDate() { return false; } /** * 离开公司 */ public void exitCompany() { if (isNeedPrintDate()) { System.out.print(new Date().toLocaleString()+"-->"); } System.out.println(name + "离开公司"); }
超类中添加了一个isNeedPrintDate方法,且默认返回false,不打印时间。如果某子类需要调用打印时间,可以复写改钩子方法,返回true,比如,程序猿复写了这个方法:
package com.zhy.pattern.template; public class ITWorker extends Worker { public ITWorker(String name) { super(name); } @Override public void work() { System.out.println(name + "写程序-测bug-fix bug"); } @Override public boolean isNeedPrintDate() { return true; } }
最后再看下测试结果:
-----------------work start --------------- 鸿洋进入公司 鸿洋打开电脑 鸿洋写程序-测bug-fix bug 鸿洋关闭电脑 2014-5-19 19:17:05-->鸿洋离开公司 -----------------work end ---------------
好了,关于钩子,超类中可提供默认实现或者空实现,子类可覆盖或者不覆盖,具体根据需求来定。
最近恰好,再写一个爬虫程序,用到了模版方法模式,给大家分享下:
需求分析:程序需要对特定的20个网站进行抓取数据;每个网站页面返回的结果数据不同,url不同,参数不同等;但是抓取的过程是一致的。
于是我就这样的设计:
a、定义一个规则Rule类(包含了:url,params,request_method,以及返回哪块数据【根据选择器】)
b、通过Rule进行抓取数据
c、对数据进行处理
我把上面3个步骤定义了算法的骨架,b为超类实现,a、c由子类实现:
package com.zhy.pattern.template; public abstract class AbsExtractInfo { /** * 抓取的算法骨架 */ public void extract() { Rule rule = generateRule() ; List<Element> eles = getInfosByRule(rule); dealResult(eles); } /** * 生成一个Rule * @return */ public abstract Rule generateRule(); /** * 抓取的实现 * @param rule * @return */ private List<Element> getInfosByRule(Rule rule) { // the implements omitted } /** * 处理抓取的结果 * @param results */ public void dealResult(List<Element> results); }
其中GenerateRule这个方法,恰好是工厂模式中的抽象方法模式(定义一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法模式把类实例化的过程推迟到子类),如果你忘记了,可以查看设计模式 工厂模式 从卖肉夹馍说起
好了,就到这里,最后欢迎大家留言。
- package com.zhy.pattern.template;
- public class QAWorker extends Worker
- {
- public QAWorker(String name)
- {
- super(name);
- }
- @Override
- public void work()
- {
- System.out.println(name + "写测试用例-提交bug-写测试用例");
- }
- }
项目经理:
- package com.zhy.pattern.template;
- public class ManagerWorker extends Worker
- {
- public ManagerWorker(String name)
- {
- super(name);
- }
- @Override
- public void work()
- {
- System.out.println(name + "打dota...");
- }
- }
下面我们测试下:
- package com.zhy.pattern.template;
- public class Test
- {
- public static void main(String[] args)
- {
- Worker it1 = new ITWorker("鸿洋");
- it1.workOneDay();
- Worker it2 = new ITWorker("老张");
- it2.workOneDay();
- Worker hr = new HRWorker("迪迪");
- hr.workOneDay();
- Worker qa = new QAWorker("老李");
- qa.workOneDay();
- Worker pm = new ManagerWorker("坑货");
- pm.workOneDay();
- }
- }
输出结果:
- -----------------work start ---------------
- 鸿洋进入公司
- 鸿洋打开电脑
- 鸿洋写程序-测bug-fix bug
- 鸿洋关闭电脑
- 鸿洋离开公司
- -----------------work end ---------------
- -----------------work start ---------------
- 迪迪进入公司
- 迪迪打开电脑
- 迪迪看简历-打电话-接电话
- 迪迪关闭电脑
- 迪迪离开公司
- -----------------work end ---------------
- -----------------work start ---------------
- 老李进入公司
- 老李打开电脑
- 老李写测试用例-提交bug-写测试用例
- 老李关闭电脑
- 老李离开公司
- -----------------work end ---------------
- -----------------work start ---------------
- 坑货进入公司
- 坑货打开电脑
- 坑货打dota...
- 坑货关闭电脑
- 坑货离开公司
- -----------------work end ---------------
好了,恭喜你,又学会一个设计模式,模版方法模式。
下面看下模版方法模式类图,和我们程序的类图:
模版方式里面也可以可选的设置钩子,比如现在希望记录程序员离开公司的时间,我们就可以在超类中添加一个钩子:
- public boolean isNeedPrintDate()
- {
- return false;
- }
- /**
- * 离开公司
- */
- public void exitCompany()
- {
- if (isNeedPrintDate())
- {
- System.out.print(new Date().toLocaleString()+"-->");
- }
- System.out.println(name + "离开公司");
- }
超类中添加了一个isNeedPrintDate方法,且默认返回false,不打印时间。如果某子类需要调用打印时间,可以复写改钩子方法,返回true,比如,程序猿复写了这个方法:
- package com.zhy.pattern.template;
- public class ITWorker extends Worker
- {
- public ITWorker(String name)
- {
- super(name);
- }
- @Override
- public void work()
- {
- System.out.println(name + "写程序-测bug-fix bug");
- }
- @Override
- public boolean isNeedPrintDate()
- {
- return true;
- }
- }
- -----------------work start ---------------
- 鸿洋进入公司
- 鸿洋打开电脑
- 鸿洋写程序-测bug-fix bug
- 鸿洋关闭电脑
- 2014-5-19 19:17:05-->鸿洋离开公司
- -----------------work end ---------------
好了,关于钩子,超类中可提供默认实现或者空实现,子类可覆盖或者不覆盖,具体根据需求来定。
最近恰好,再写一个爬虫程序,用到了模版方法模式,给大家分享下:
需求分析:程序需要对特定的20个网站进行抓取数据;每个网站页面返回的结果数据不同,url不同,参数不同等;但是抓取的过程是一致的。
于是我就这样的设计:
a、定义一个规则Rule类(包含了:url,params,request_method,以及返回哪块数据【根据选择器】)
b、通过Rule进行抓取数据
c、对数据进行处理
我把上面3个步骤定义了算法的骨架,b为超类实现,a、c由子类实现:
- package com.zhy.pattern.template;
- public abstract class AbsExtractInfo
- {
- /**
- * 抓取的算法骨架
- */
- public void extract()
- {
- Rule rule = generateRule() ;
- List<Element> eles = getInfosByRule(rule);
- dealResult(eles);
- }
- /**
- * 生成一个Rule
- * @return
- */
- public abstract Rule generateRule();
- /**
- * 抓取的实现
- * @param rule
- * @return
- */
- private List<Element> getInfosByRule(Rule rule)
- {
- // the implements omitted
- }
- /**
- * 处理抓取的结果
- * @param results
- */
- public void dealResult(List<Element> results);
- }
其中GenerateRule这个方法,恰好是工厂模式中的抽象方法模式(定义一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法模式把类实例化的过程推迟到子类),如果你忘记了,可以查看设计模式 工厂模式 从卖肉夹馍说起
好了,就到这里,最后欢迎大家留言。
-
顶
- 25
-
踩
- 1
我的同类文章
- •设计模式 状态模式 以自动售货机为例2014-05-20阅读6819
- •设计模式 适配器模式 以手机充电器为例2014-05-14阅读4954
- •设计模式 单例模式2014-04-25阅读5988
- •设计模式 装饰者模式 带你重回传奇世界2014-04-21阅读7223
- •设计模式 策略模式 以角色游戏为背景2014-04-19阅读7504
- •设计模式 外观模式 一键电影模式2014-05-14阅读4326
- •设计模式 命令模式 之 管理智能家电2014-04-27阅读4644
- •设计模式 工厂模式 从卖肉夹馍说起2014-04-25阅读7033
- •设计模式 观察者模式 以微信公众服务为例2014-04-20阅读8399
-
猜你在找
核心技术类目
-
- 长期为您推荐优秀博文、开源项目、视频等,进入还有好玩的等着你,欢迎扫一扫。
- 【Android 5.x】(9)
- 【Android 精彩案例】(35)
- 【Android 源码解析】(29)
- 【Android 自定义控件实战】(29)
- 【Android 自定义控件之起步】(7)
- 【Android 快速开发】(12)
- 【Android 原生开发游戏】(3)
- 【Java 并发专题】(15)
- 【android 进阶之路】(62)
- 【Java 设计模式】(10)
- 【Android 百度地图】(4)
- 【html5 css3精彩案例】(14)
- 【Android github 控件】(10)
- 【Android 基础】(16)
- 【Javascript 】(9)
- 【rabbitMQ 用法】(5)
12楼 baozhonghaha2016-03-28 10:20发表 [回复]-
-
恭喜,恭喜。。。大神新婚快乐。。
11楼 无泪无悔902016-02-05 15:28发表 [回复]-
-
看到坑货是打dota的,我瞬间觉得我的人生有了目标
10楼 corffen2016-01-30 16:19发表 [回复]-
-
看到坑货二字 我终于忍不住要评论了 嘎嘎嘎
9楼 jacksgun2015-11-12 19:36发表 [回复]-
-
这个例子太逗了。看的我都笑了
8楼 _ontheway_2015-08-17 17:18发表 [回复]-
-
学习了,这模式挺常用的,不过现在才知道这也是一种设计模式
7楼 牛迁迁2015-08-17 09:49发表 [回复]-
-
学习了,理解的不错。
6楼 carbit_tianpan2015-06-14 21:46发表 [回复]-
-
真的很受用
5楼 oilover2015-06-13 22:05发表 [回复]-
-
写的很好!受教了!
4楼 大梦未觉2014-12-25 09:03发表 [回复]-
-
不错,写得挺简洁明了的
3楼 superdcj2014-11-27 11:31发表 [回复]-
-
代码36行少了一个abstract修饰符
public void dealResult(List<Element> results);
2楼 dodoniao2014-09-18 13:37发表 [回复]-
-
可否把爬虫的代码
放到一个公共的地方,大家学习下?
谢谢了
1楼 while-living2014-07-23 17:53发表 [回复]-
-
你英文名叫dota吧。支持支持,但感觉就算知道有这模式,对于要在什么时候用还是不清楚啊,这个只能靠经验了吧。