文档章节

Java设计模式之模板方法模式

断桥残雪断桥残雪
 断桥残雪断桥残雪
发布于 2015/08/15 23:08
字数 1830
阅读 579
收藏 10

模板方法模式简介

模板方法(Template method),顾名思义,就是做一些任务的通用流程。如网上有许多自我介绍模板、推荐信模板,即开头和结尾可能都是差不多的内容,而中间需要客户去修改一下即可使用。设计模式源自生活,模板方法就在类似的场景下诞生了。模板方法是指写一个操作中的算法框架,而将一些步骤延迟到子类中去实现,这样就使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。

模板方法的设计方法

模板方法通常会设计一个抽象类,内部定义一些需要子类去实现的抽象方法,因为这些方法可能因不同的子类会有不同的实现,因此定义为抽象方法。另外,抽象类中应该有一个或多个模板方法,即固定好的框架,而且这个方法的修饰符通常定义为final,这样做是为了防止子类去覆写这个模板,因为我们认为模板是固定的,不容修改。而在这个固定的模板方法内部,会调用那些抽象方法,来一步一步实现整个算法的流程。通常,子类要去继承这个抽象父类,并根据自己的业务逻辑实现里面的抽象方法。

模板方法的特点

模板方法清晰地划定了某一类业务的变与不变,为一类业务做好了流程框架,为子类提供了公共的代码,并且子类的行为完全由父类来控制,实现了代码的可维护性和可扩展性。父类不容修改,子类可以去扩展,很好地符合了设计模式的开闭原则——对修改封闭,对扩展开放。

注意模板方法设计模式与抽象类设计的区别,抽象类这种设计模式是父类定义一些抽象方法,让子类去实现,因此子类通常有更多的自由空间;而模板方法中是父类定义好了算法框架,子类去实现父类其中的抽象方法,因此子类的作用可以影响父类。

模板方法的应用示例

背景介绍

假设现在要制作一些饮料产品,比方说要泡茶和咖啡。泡茶和泡咖啡的流程大体上可以分为四步,第一将水煮沸,第二烘焙原料,第三倒入杯中,第四加入调料。通常第一步和第三步动作是一样的,所以我们可以在父类中将方法直接写好,而第二步和第四步则随着泡茶还是泡咖啡有所不同,因此我们设计为抽象方法,让子类去实现。而这四步整体上又是泡饮料的固定流程,所以我们将这四步封装在一个方法中,并且设置这个方法的修饰符为final,以防子类去修改它。

模板方法

下面先写出模板方法的代码:


package com.template;
/**
 * 模板模式
 * 抽象基类,为所有子类提供算法框架
 * 业务:提神饮料
 * @author zzw
 *
 */
public abstract class RefreshBeverage {
	
	/*
	 * 制备饮料的模板方法,指定算法框架
	 */
	//阻止子类对模板方法进行复写
	public final void prepareBeverageTemplate() {
		//步骤1:将水煮沸
		boilWater();
		
		//步骤2:炮制饮料
		brew();
		
		//步骤3:倒入杯中
		pourInCup();
		
		//步骤4:加入调料(引入钩子函数,从用户角度出发,可选择性)
		if(isCustomerWantCondiments()) {
			addCondiments();
		}
	}

	/*
	 * Hook,钩子函数
	 * 提供一个默认或空的实现
	 * 具体子类可以自行决定是否挂钩以及如何挂钩
	 * 询问用户是否加入调料
	 */
	protected boolean isCustomerWantCondiments() {
		// 默认设置
		return true;
	}

	//抽象方法,由子类实现
	protected abstract void addCondiments();
	
	private void pourInCup() {
		// 倒入杯中
		System.out.println("倒入杯中");
	}

	//抽象方法,由子类实现
	protected abstract void brew();
		
	private void boilWater() {
		// 将水煮沸
		System.out.println("将水煮沸");
	}

}



子类实现

由于泡茶喝泡咖啡的具体实现有所不同,并且还可以使用钩子函数来判断用户是否需要加调料,这样使得流程更具人性化。

泡茶:


package com.template;
/**
 * 茶叶制备的具体实现
 * 子类
 * @author zzw
 *
 */
public class TeaBeverage extends RefreshBeverage {

	
	@Override
	protected void addCondiments() {
		// TODO Auto-generated method stub

		System.out.println("加入茶叶调料");
	}

	@Override
	protected void brew() {
		// TODO Auto-generated method stub

		System.out.println("烘焙茶叶");
	}	
	

}



泡咖啡:



package com.template;

public class CoffeeBeverage extends RefreshBeverage {

	@Override
	protected void addCondiments() {
		// TODO Auto-generated method stub
		
		System.out.println("加入咖啡调料");
	}

	@Override
	protected void brew() {
		// TODO Auto-generated method stub
		
		System.out.println("烘焙咖啡");
	}
	
}



由于中国茶一般不加调料,所以这里如果引入一个中国茶的话,在继承茶的基础上,将是否加调料设为不加即可。



package com.template;
/**
 * 制备中式茶
 * 不需要加调料
 * 因此选择挂钩函数
 * 其他的则继承茶的制作
 * @author Administrator
 *
 */
public class ChineseTeaBeverage extends TeaBeverage {

	@Override
	protected boolean isCustomerWantCondiments() {
		// TODO Auto-generated method stub
		return false;
	}

	
}



钩子函数

钩子实际上是一个处理消息的程序段,通过系统调用,把它挂入系统。每当特定的消息发出,在没有到达目的窗口前,钩子程序就先捕获该消息,亦即钩子函数先得到控制权。这时钩子函数即可以加工处理(改变)该消息,也可以不作处理而继续传递该消息,还可以强制结束消息的传递。
对每种类型的钩子由系统来维护一个钩子链,最近安装的钩子放在链的开始,而最先安装的钩子放在最后,也就是后加入的先获得控制权。如本博文中提到的是否加入调料即为一种钩子函数,它对是否加调料具有决定权。
如果指定确定的线程,即为线程专用钩子;如果指定为空,即为全局钩子。其中,全局钩子函数必须包含在DLL(动态链接库)中,而线程专用钩子还可以包含在可执行文件中。得到控制权的钩子函数在完成对消息的处理后,如果想要该消息继续传递,那么它必须调用另外一个SDK中的API函数CallNextHookEx来传递它。钩子函数也可以通过直接返回TRUE来丢弃该消息,并阻止该消息的传递。



模板方法模式的使用场景

模板方法可以用于一次性实现一个算法的不变的部分,并将可变的部分留给子类去实现;子类的公共代码部分应该被提炼到父类中去写好,防止代码重复编写;控制子类的扩展,模板方法只允许在特定点调用钩子函数,这样就只允许在这些点进行扩展。


© 著作权归作者所有

断桥残雪断桥残雪
粉丝 53
博文 139
码字总数 94909
作品 0
广州
程序员
私信 提问
设计模式15——Template Method设计模式

Template Method模板方法设计模式定义一个操作中算法的骨架,将具体步骤的执行延迟到子类中实现。Java中的抽象类就是使用了模板方法设计模式。模板方法设计模式结构如下: 以文档处理为例,T...

小米米儿小
2014/01/24
214
0
设计模式 2014-12-19

book: 阎宏《JAVA与模式》 架构设计栏目 http://blog.csdn.net/enterprise/column.html 概要: http://bbs.csdn.net/forums/Embeddeddriver 23种设计模式分别是: 1.单例模式 2.工厂方法模式...

jayronwang
2014/12/19
289
0
Java语言编程学习之Lambda表达式设计和架构的原则[图]

Java语言编程学习之Lambda表达式设计和架构的原则[图]: 大家都知道,Lambda表达式是对Java语言的一点简单改进,在JDK标准类库中,运行它的方式各种各样。但是大多数的Java代码都不是由开发J...

原创小博客
2018/07/17
30
0
Java语言编程学习之Lambda表达式设计和架构的原则

大家都知道,Lambda表达式是对Java语言的一点简单改进,在JDK标准类库中,运行它的方式各种各样。但是大多数的Java代码都不是由开发JDK的程序猿写的,而是像我们这样的普通程序猿。 很多人都...

JAVA高级架构开发
2018/08/19
0
0
java 23种设计模式 深入理解

以下是学习过程中查询的资料,别人总结的资料,比较容易理解(站在各位巨人的肩膀上,望博主勿究) 创建型 抽象工厂模式 http://www.cnblogs.com/java-my-life/archive/2012/03/28/2418836.html ...

wc_飞豆
2018/03/16
176
0

没有更多内容

加载失败,请刷新页面

加载更多

领域驱动中的“贫血症和失忆症” --实践领域驱动--原文

贫血症严重危害着人类健康,并且伴随有危险的副作用。当贫血领域对象被首次提出来时,它并不是一个博得赞美的词汇,它描述的是一个缺少内在行为领域对象。奇怪的是,人们对于贫血领域对象的态...

还仙
28分钟前
5
0
条码打印软件中标签预览正常打印无反应怎么解决

在使用条码打印软件制作标签时,有客户反馈,标签打印预览正常的,但是打印无反应,咨询是怎么回事?今天针对这个情况,可以参考以下方法进行解决。 一、预览正常情况下,打印没反应 (1)在条码...

中琅软件
38分钟前
5
0
判断字符串的时候

判断字符串的时候一定把常量房前边, //报警程度 String leve = vo.getDeviceAlertDeal().getWarnLevel(); if(("0").equals(leve)) { row.add("无报警"); }else if(("1").equals(leve)) { ro......

简小姐
39分钟前
7
0
Linux maven3.6.2 install

PS:安装 maven 之前请先安装 jdk 1.安装 wget 命令(安装过就不用了) yum -y install wget 2.寻找需要的 maven 版本 https://maven.apache.org/download.cgi 3.进入 /var/local 文件夹 cd...

东方神祇
41分钟前
5
0
Tomcat源码分析二:先看看Tomcat的整体架构

Tomcat源码分析二:先看看Tomcat的整体架构 Tomcat架构图 我们先来看一张比较经典的Tomcat架构图: 从这张图中,我们可以看出Tomcat中含有Server、Service、Connector、Container等组件,接下...

flygrk
43分钟前
6
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部