【java设计模式】之 模板方法(Template Method)模式
1. 模板方法的一个实例
这一节主要来学习一下设计模式中的模板方法模式。我们先来看一个例子:假如现在老板让你做一个汽车的模型,要求只要完成基本功能即可,不考虑扩展性,那你会怎么做呢?我们首先会根据经验设计一个类图:
由这个类图可知,非常简单的实现了悍马车,该车有两个型号H1和H2。那现在我们开始实现这两个型号的悍马车,首先我们得把抽象类写好,然后两个不同的模型实现类通过简单的继承就可以实现要求。首先看看抽象类的代码:
public abstract class HummerModel {
public abstract void start(); //发动
public abstract void stop(); //停止
public abstract void alarm(); //鸣笛
public abstract void engineBoom(); //轰鸣
public abstract void run(); //车总归要跑
}
简单到不行,下面我们来实现两个悍马的模型:
//悍马H1
public class HummerH1 extendsHummerModel { @Override
public void start() {
System.out.println("H1发动……");
} @Override
public void stop() {
System.out.println("H1停止……");
} @Override
public void alarm() {
System.out.println("H1鸣笛……");
} @Override
public void engineBoom() {
System.out.println("H1轰鸣……");
} @Override
public void run() {
this.start();
this.engineBoom();
this.alarm();
this.stop();
}
} //悍马H2
public class HummerH2 implements HummerModel { @Override
public void start() {
System.out.println("H2发动……");
} @Override
public void stop() {
System.out.println("H2停止……");
} @Override
public void alarm() {
System.out.println("H2鸣笛……");
} @Override
public void engineBoom() {
System.out.println("H2轰鸣……");
} @Override
public void run() {
this.start();
this.engineBoom();
this.alarm();
this.stop();
}
}
很明显,已经发现代码有点问题了,两个悍马的run方法完全相同。所以这个run方法应该出现在抽象类中,不应该在实现类中,抽象是所有子类的共性封装。所以我们修改一下抽象类:
public abstract class HummerModel {
public abstract void start(); //发动
public abstract void stop(); //停止
public abstract void alarm(); //鸣笛
public abstract void engineBoom(); //轰鸣
public void run() { //车总归要跑
this.start();
this.engineBoom();
this.alarm();
this.stop();
}
}
这样两个实现类就不用实现run方法了,可以直接拿来用。其实,这就是模板方法模式。
2. 模板方法模式的定义
模板方法模式很简单,它的定义是:Define the skeleton of an algorithm in an operation, deferring some steps to subclasses. Template Method lets subclasses define certain steps of an algorithm without changing the algorithm's structure. 即定义一个操作中的算法框架,而将一些步骤延迟到子类中,使得子类可以不改变一个算法的结构即可冲定义该算法的某些特定步骤。模板方法模式的通用类图如下:
模板方法模式确实很简单,仅仅使用了Java的继承机制,但是它是一个应用非常广泛的模式,其中AbstractClass叫做抽象模板,它的方法分为两类:基本方法(由子类去实现)和模板方法(可以有一个或多个,也就是一个框架,实现对基本方法的调度,完成固定的逻辑)。为了防止恶意的操作,一般模板方法上都添加上final关键字,不允许被覆写。我们来看一下AbstractClass模板:
public abstract class AbstractClass {
//基本方法
protected abstract void doSomething();
protected abstract void doAnything();
//模板方法
public void templateMethod() {
//调用基本方法,完成相关的逻辑
this.doAnything();
this.doSomething();
}
}
具体实现类就不写了……
3. 模板方法模式的优缺点
优点:
1)封装不变部分,扩展可变部分:把认为不变部分的算法封装到父类实现,可变部分则可以通过继承来实现,很容易扩展。
2)提取公共部分代码,便于维护:上面悍马的例子就是个很好的解释。
3)行为由父类控制,由子类实现。
缺点:
模板方法模式颠倒了我们平常的设计习惯:抽象类负责声明最抽象、最一般的事物属性和方法,实现类实现具体的事物属性和方法。在复杂的项目中可能会带来代码阅读的难度。
4. 模板方法模式的扩展
还是上面那个悍马的例子,现在老板说这车干嘛跑起来就要鸣笛,太吵了,难道不是应该让用户决定它是否要鸣笛么?好像确实是这样的……那好办,我们可以修改一下抽象模板类中的方法:
public abstract class HummerModel {
protected abstract void start(); //发动
protected abstract void stop(); //停止
protected abstract void alarm(); //鸣笛
protected abstract void engineBoom(); //轰鸣
final public void run() { //车总归要跑
this.start();
this.engineBoom();
if(this.isAlarm()) {//想让它叫就叫,不想就不叫
this.alarm();
}
this.stop();
}
protected boolean isAlarm() { //我们加了一个判断方法,默认返回true
return true;
}
}
我们在模板类中增加了一个判断方法来判断是否要鸣笛,现在就好办了,具体实现类只要重写这个方法就可以做到人为控制是否要鸣笛了,下面我们来看一下实现类:
public class HummerH1 extends HummerModel {
private boolean alarmFlag = true; //判断标记
@Override
public void start() {
System.out.println("H1发动……");
}
@Override
public void stop() {
System.out.println("H1停止……");
}
@Override
public void alarm() {
System.out.println("H1鸣笛……");
}
@Override
public void engineBoom() {
System.out.println("H1轰鸣……");
}
@Override
protected boolean isAlarm() { //覆写isAlarm方法,返回判断标记
return this.alarmFlag;
}
public void setAlarm(boolean isAlarm) { //设置判断标记
this.alarmFlag = isAlarm;
}
}
这个实现很好,我们在实现类中定义一个判断标记,然后对外提供一个public接口setAlarm来让外界设置这个判断标记,这就像是开关一样,想让它ture和false都行。这个isAlarm方法俗称钩子方法。有了钩子方法的模板方法模式才算完美,大家可以想象一下,由子类的一个方法返回值决定公共部分的执行结果,这个是很有吸引力的。我们来测试一下:
public class Test {
public static void main(String[] args) throws IOException {
System.out.println("----H1型焊马-----");
System.out.println("是否需要喇叭声响? 0-不需要 1-需要");
String type = new BufferedReader(new InputStreamReader(System.in)).readLine();
/*Scanner scanner = new Scanner(System.in);//创建输入流扫描器
String type=scanner.nextLine();*/
HummerH1 h1 = new HummerH1();
if(type.equals("0")) {
h1.setAlarm(false);
}
h1.run();
}
}
当输入不同的指令后,就会决定不同的动作:即要不要鸣笛,至此,这个模板方法模式就介绍完了。
【java设计模式】之 模板方法(Template Method)模式的更多相关文章
- 行为型设计模式之模板方法(TEMPLATE METHOD)模式 ,策略(Strategy )模式
1 模板方法(TEMPLATE METHOD)模式: 模板方法模式把我们不知道具体实现的步聚封装成抽象方法,提供一些按正确顺序调用它们的具体方法(这些具体方法统称为模板方法),这样构成一个抽象基类.子 ...
- Java设计模式之 — 模板方法(Template Method)
转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/8744002 今天你还是像往常一样来上班,一如既往地开始了你的编程工作. 项目经理告 ...
- 一天一个设计模式——模板方法(Template Method)模式
一.模式说明 现实世界中的模板是用于将事物的结构规律予以固定化.标准化的成果,它体现了结构形式的标准化.例如镂空文字印刷的模板,通过某个模板印刷出来的文字字体大小都是一模一样,但是具体使用什么材质的颜 ...
- 宋宝华:Linux设备驱动框架里的设计模式之——模板方法(Template Method)
本文系转载,著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 作者: 宋宝华 来源: 微信公众号linux阅码场(id: linuxdev) 前言 <设计模式>这本经典 ...
- 设计模式二--模板方法Template method
模式分类: 书籍推荐:重构-改善既有代码的设计 重构获得模式 设计模式:现代软件设计的特征是"需求的频繁变化".设计模式的要点是 "寻找变化点,然后在变化点处应用设计模式 ...
- 设计模式之---模板方法template method的使用
在面向对象系统的分析与设计过程中经常会遇到这样一种情况:对于某一个业务逻辑(算法实现)在不同的对象中有不同的细节实现,但是逻辑(算法)的框架(或通用的应用算法)是相同的.Template Method ...
- 封装算法: 模板方法(Template Method)模式
template method(模板方法)模式是一种行为型设计模式.它在一个方法中定义了算法的骨架(这种方法被称为template method.模板方法),并将算法的详细步骤放到子类中去实现.tem ...
- 设计模式之模板方法(Template Method)
在整理模板方法之前,先来说点废话吧.除了记录学习总结,也来记录一下生活吧. 我们公司的老板在北京,老板也会因为项目来公司,不过不是天天来.公司有个同事,只要老板不在就天天迟到,而且一天比一天晚,经常来 ...
- 设计模式六: 模板方法(Template Method)
简介 模板方法属于行为型模式的一种. 实现层面上, 在抽象类中定义了算法或流程的骨架, 将其中易变的部分延迟到子类实现, 也就是允许它的子类实现其中的某些步骤. 模板方法适用于算法不变, 但算法中某些 ...
- 行为型设计模式之模板方法(Template Method)
结构 意图 定义一个操作中的算法的骨架,而将一些步骤延迟到子类中.Te m p l a t e M e t h o d 使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤. 适用性 一次性 ...
随机推荐
- Hibernate---基础配置之日志信息slf 及搭建日志环境
slf日志接口, 实现有slf4j nodep, log4j hibernate里我们一般用 log4j,所以删除之前创建的hibernate 包里的 slf4j-nop包, 加入log4j-1.2. ...
- iOS下bound,center和frame
本文转发至:http://www.xuebuyuan.com/1846606.html 在写程序的时候发现,iOS下的坐标.位置很容易弄乱,特别是在不同的坐标系统中,必须完成弄明白一些概念才能做相应的 ...
- iOS多视图传值方式之通知传值(NSNotification;NSNotificationCenter)
iOS传值方式之5:通知传值 第一需要发布的消息,再创建NSNotification通知对象,然后通过NSNotificationCenter通知中心发布消息(NSNotificationCenter ...
- struts2.0 s标签_小小鸟_百度空间
struts2.0 s标签 1. Struts2页面开发中常用标签使用说明 1.1.往action里传值的使用方式: <input name="userName" type= ...
- 无限循环小数POJ1930
题意:给定一个无限循环小数,求其分数形势,要求分母最小 分析:看了别人的题解才做出来的,将无限循环小数转化成分数,分为纯循环和混循环两种形式. (1)对于纯循环:用9做分母,有多少个循环数就几个9,比 ...
- svn + jenkins + maven 实现java环境的自动化构建和部署
1. 环境说明: 系统CentOS 7 x64 IP: 10.6.0.126 1.1 首先安装配置 svn Centos 7 通过yum 安装svn 既可, 版本为1.7.14 # yum -y ...
- 用命令行使用soot反编译生成jimple
使用工具:soot-2.5.0.jar 注意:soot-2.5.0.jar必须使用Java1.7以及之前的版本,使用Java1.8会发生错误. 修改jdk的方法是在设置java_home的路径的时候, ...
- (简单) POJ 1278 Catch That Cow,回溯。
Description Farmer John has been informed of the location of a fugitive cow and wants to catch her i ...
- FAB、TextInputLayout及Snackbar笔记
FloatingActionButton 由于FloatingActionButton是重写ImageView的,所有FloatingActionButton拥有ImageView的一切属性. 控制F ...
- C语言-while循环
循环是结构化程序设计的基本结构之一,它和顺序控制.选择结构共同作为各种复杂程序的基本构造单元(摘自谭浩强的<C程序设计>. 一.while循环: 1.使用while循环控制输出0到9十个数 ...