模板方法模式,一般是为了统一子类的算法实现步骤,所使用的一种手段或方式。它在父类定义一系列的算法步骤,而将具体实现推迟到子类。
通常情况下,模板方法模式用于定义构建某个对象的步骤与顺序,或定义一个算法的骨架。
通常来说父类定义的步骤和顺序或算法骨架,是不允许子类覆盖的,所以在某些场景中,可以直接将父类提供的骨架方法声明为final类型的。
下面模拟构建一个html页面,来应用模板方法模式:
父类定义构建一个html页面的步骤算法:
public abstract class AbstractPageBuild { private StringBuffer stringBuffer = new StringBuffer(); /** * 按顺序构建算法骨架 * * @return */ public String build() { // 首先加入doctype,因为都是html页面,父类不需要推迟给子类实现,直接在父类实现 stringBuffer .append("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">"); // 页面下面就是成对的Html标签,也不需要子类实现,直接在父类实现 stringBuffer.append("<html xmlns=\"http://www.w3.org/1999/xhtml\">"); // 下面就是Head标签里的内容,我们父类做不了主,推迟到子类实现,所以我们定义一个抽象方法,让子类必须实现 appendHead(stringBuffer); // 下面是Body标签的内容,我们父类依然做不了主,推迟到子类实现 appendBody(stringBuffer); // html的关闭标签 stringBuffer.append("</html>"); return stringBuffer.toString(); } /** * 模板方法-添加Head * * @param stringBuffer */ protected abstract void appendHead(StringBuffer stringBuffer); /** * 模板方法-添加body * * @param stringBuffer */ protected abstract void appendBody(StringBuffer stringBuffer); }
public class MyPageBuild extends AbstractPageBuild { @Override protected void appendHead(StringBuffer stringBuffer) { stringBuffer.append("<head><title>你好</title></head>"); } @Override protected void appendBody(StringBuffer stringBuffer) { stringBuffer.append("<body><h1>你好,世界!</h1></body>"); } public static void main(String[] args) { AbstractPageBuild page = new MyPageBuild(); String html = page.build(); System.out.println(html); } }
子类继承父类,并实现父类必须要实现的方法,来完成一个html页面构建。
并通过多态来调用父类的构建方法。
执行结果如下:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><title>你好</title></head><body><h1>你好,世界!</h1></body></html>
以上就是模板方法模式最基本实现。
模板方法还有一种使用方式,为了给子类足够的自由度,可以提供一些方法供子类覆盖,去实现一些骨架中不是必须但却可以自定义实现的步骤。
比如将head标签细化为title,meta,link,script,除了title,body子类必须覆盖外,其它可选择性覆盖
public abstract class AbstractPageBuild2 { private StringBuffer stringBuffer = new StringBuffer(); /** * 按顺序构建算法骨架 * * @return */ public String build() { // 首先加入doctype,因为都是html页面,父类不需要推迟给子类实现,直接在父类实现 stringBuffer .append("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">"); // 页面下面就是成对的Html标签,也不需要子类实现,直接在父类实现 stringBuffer.append("<html xmlns=\"http://www.w3.org/1999/xhtml\">"); // 下面就是Head标签里的内容,我们父类做不了主,推迟到子类实现,所以我们定义一个抽象方法,让子类必须实现 stringBuffer.append("<head>"); appendTitle(stringBuffer); appendMeta(stringBuffer); appendLink(stringBuffer); appendScript(stringBuffer); stringBuffer.append("</head>"); // 下面是Body标签的内容,我们父类依然做不了主,推迟到子类实现 appendBody(stringBuffer); // html的关闭标签 stringBuffer.append("</html>"); return stringBuffer.toString(); } /** * 子类选择性覆盖 * * @param stringBuffer */ protected void appendMeta(StringBuffer stringBuffer) { } /** * 子类选择性覆盖 * * @param stringBuffer */ protected void appendLink(StringBuffer stringBuffer) { } /** * 子类选择性覆盖 * * @param stringBuffer */ protected void appendScript(StringBuffer stringBuffer) { } /** * 模板方法-添加Title-子类必须覆盖 * * @param stringBuffer */ protected abstract void appendTitle(StringBuffer stringBuffer); /** * 模板方法-添加body-子类必须覆盖 * * @param stringBuffer */ protected abstract void appendBody(StringBuffer stringBuffer); }
如果想让子类选择性覆盖,可以将方法实现为一个空方法。
public class MyPageBuild2 extends AbstractPageBuild2 { @Override protected void appendMeta(StringBuffer stringBuffer) { stringBuffer.append("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />"); } @Override protected void appendTitle(StringBuffer stringBuffer) { stringBuffer.append("<title>你好</title>"); } @Override protected void appendBody(StringBuffer stringBuffer) { stringBuffer.append("<body><h1>你好,世界!</h1></body>"); } public static void main(String[] args) { AbstractPageBuild2 page = new MyPageBuild2(); String html = page.build(); System.out.println(html); } }
子类可以自由选择性覆盖父类的方法,通过多态来调用父类的构建算法过程
执行结果如下:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><title>你好</title><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /></head><body><h1>你好,世界!</h1></body></html>
通常情况下,模板方法模式用于定义构建某个对象的步骤与顺序,或者定义一个算法的骨架。
我们刚才的示例明显就是构建一个String对象的过程,在这里要声明一点,对于模板方法模式,父类提供的构建步骤和顺序或者算法骨架,通常是不希望甚至是不允许子类去覆盖的,所以在某些场景中,可以直接将父类中提供骨架的方法声明为final类型。
说到模板方法模式,我们JDK当中有一个类与它还有一个不得不说的故事,那就是类加载器。
JDK类加载器可以大致分为三类,分别是启动类加载器,扩展类加载器,以及应用程序加载器。
这三者加载类的路径分别为如下:
启动类加载器:JAVA_HOME/lib目录下,以及被-Xbootcalsspath参数设定的路径,不过启动类加载器加载的类是有限制的,如果JVM不认识的话,你放在这些目录下也没用。
扩展类加载器:JAVA_HOME/lib/ext目录下,以及被java.ext.dirs系统变量指定的路径。
应用程序类加载器:用户自己的类路径(classpath),这个类加载器就是我们经常使用的系统类加载器,并且JDK中的抽象类ClassLoader的默认父类加载器就是它。
在这里为什么说类加载器和模板方法模式有关呢,是因为ClassLoader类就使用了模板模式,去保证类加载过程中的唯一性。LZ先给各位看下这个类当中的模板模式的应用。
public abstract class ClassLoader { //这是一个重载方法 public Class<?> loadClass(String name) throws ClassNotFoundException { return loadClass(name, false); } //这里就是父类算法的定义 protected synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { Class c = findLoadedClass(name); if (c == null) { try { if (parent != null) { c = parent.loadClass(name, false); } else { c = findBootstrapClass0(name); } } catch (ClassNotFoundException e) { c = findClass(name); } } if (resolve) { resolveClass(c); } return c; } //这里留了一个方法给子类选择性覆盖 protected Class<?> findClass(String name) throws ClassNotFoundException { throw new ClassNotFoundException(name); } }
LZ截取了主要的部分,为了突出这三个方法。在上面LZ加了简单的注释,相信经过刚才的介绍,各位应该能看出来这是一个模板方法模式,只是它没有定义抽象方法,因为findClass这个方法,并不是必须实现的,所以JDK选择留给程序员们自己选择是否要覆盖。
从代码上我们可以看出,在ClassLoader中定义的算法顺序是。
1,首先看是否有已经加载好的类。
2,如果父类加载器不为空,则首先从父类类加载器加载。
3,如果父类加载器为空,则尝试从启动加载器加载。
4,如果两者都失败,才尝试从findClass方法加载。
这是JDK类加载器的双亲委派模型,即先从父类加载器加载,直到继承体系的顶层,否则才会采用当前的类加载器加载。这样做的目的刚才已经说了,是为了JVM中类的一致性。
转自:http://www.cnblogs.com/zuoxiaolong/p/pattern10.html
<audio controls="controls" style="display: none;"></audio>
相关推荐
### 深入浅出设计模式之模板方法模式 #### 一、模板方法模式概述 设计模式是软件工程中一种非常重要的技术手段,它能够帮助我们解决常见的编程问题,并提高代码的可重用性、可扩展性和可维护性。模板方法模式是一...
模板方法模式是面向对象设计模式中的行为模式之一,它在Java等面向对象编程语言中有着广泛的应用。模板方法模式的主要思想是在一个抽象类中定义一个算法的骨架,而将一些步骤延迟到子类中实现。这样,子类可以重写...
### 设计模式之模板方法模式解析 #### 一、引言 在软件开发过程中,我们经常面临这样的场景:有一些步骤是固定的,而某些步骤则可能因具体实现而异。为了解决这类问题,设计模式中引入了一种叫做“模板方法模式”的...
模板方法模式是面向对象设计中的一种行为设计模式,它在软件工程中扮演着重要的角色,尤其是在需要维护代码的可扩展性和可复用性时。这个模式的核心思想是封装不变的部分,将可变部分抽象出来,让子类进行扩展。通过...
模板方法模式是一种设计模式,属于行为设计模式,它在面向对象设计中扮演着重要的角色。这个模式定义了一个操作中的算法骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法...
模板方法模式是一种行为设计模式,它允许在定义行为框架的同时,延迟部分具体步骤到子类中实现。这种模式主要用于在父类中定义算法的骨架,而将一些步骤的实现细节留给子类去完成,从而使得不同的子类可以重用相同的...
策略模式结合模板方法模式的设计思路 策略模式结合模板方法模式是策略模式的一种变形,目的是为了解决策略模式中的一些共性问题。在策略模式中,经常会出现这样一种情况,就是发现这一系列算法的实现上存在公共功能...
模板方法模式(Template Method)是设计模式中行为型模式的一种,它定义了操作中的算法骨架,而将一些步骤延迟到子类中。使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。这个模式在C++编程中有着...
在iOS开发中,模板方法模式是一种非常实用的设计模式,它属于行为设计模式,主要用于定义算法的骨架,而将一些步骤延迟到子类中。这种方式使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。通过...
模板方法模式是一种设计模式,属于行为设计模式,它在面向对象设计中被广泛使用,用于定义算法的骨架,而将一些步骤延迟到子类中。这样,模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些特定...
模板方法模式是设计模式中的一种行为模式,它在软件工程中扮演着重要的角色,尤其是在C++这样的面向对象编程语言中。这种模式定义了一个操作中的算法骨架,而将一些步骤延迟到子类中。使得子类可以不改变一个算法的...
模板方法模式是一种行为设计模式,它在面向对象编程中扮演着重要的角色。这种模式定义了一个操作中的算法骨架,而将一些步骤延迟到子类中。这样使得子类可以在不改变算法结构的情况下,重新定义该算法的某些特定步骤...
模板方法模式是设计模式中行为型模式的一种,它在软件工程中扮演着非常重要的角色,尤其是在Java编程中。模板方法模式定义了一个操作中的算法骨架,而将一些步骤延迟到子类中。它允许子类不改变一个算法的结构即可重...
模板方法模式是一种设计模式,属于行为设计模式,它在面向对象设计中扮演着重要的角色。这个模式主要用于定义一个算法的框架,允许子类在不改变整体结构的情况下,对算法的某些步骤进行重写。模板方法模式是基于继承...
模板方法模式是设计模式中行为模式的一种,它在软件工程中扮演着重要的角色,尤其是在创建算法框架时。这种模式允许我们在抽象类中定义一个算法的骨架,而将一些步骤延迟到子类中实现,使得子类可以不改变算法的结构...
模板方法模式是一种行为设计模式,它允许在定义算法框架的同时,允许子类为一个或多个步骤提供具体的实现。这种模式通常用于代码复用,尤其是在有多种算法相似的情况下,通过抽象出公共部分,让子类专注于具体步骤的...
模板方法模式是一种设计模式,属于行为设计模式,它在面向对象编程中扮演着重要的角色。这个模式的主要目的是定义一个操作的框架,也就是算法的主干,同时允许子类在不改变算法整体结构的情况下,对其中特定步骤进行...