天天看点

【设计模式十三之模板方法模式】模板方法模式详解细说模板方法模式

(Template Method Pattern 模板方法模式

  • 细说模板方法模式
    • 细说模板方法模式
      • 定义
      • UML图示
      • 场景
        • 场景一
        • 场景二
      • 上代码
        • 代码一
        • 代码二
        • 基于UML的代码
      • 模板方法模式使用和注意事项

细说模板方法模式

提示:

博主:章飞 _906285288的博客

博客地址:http://blog.csdn.net/qq_29924041

细说模板方法模式

在生活中或者工作中很多时候面对一些标准格式文档的时候,我们都会套用一些标准的模板,然后在这些标准模板的基础上,添加一些我们自己的内容进去。比如大学时期写的论文文档,论文文档包括了封面,目录,摘要,正文,致谢,必须要按照这样的模板的论文才行。

如果你要做工作总结ppt的话,也有一些标准的PPT模板,工作成绩,前面工作内容总结,后面工作内容规划,成绩展望,等等一系列。

在生活中,离不开模板模式的应用。在代码的世界中,同样也离不开模板模式,随处可见的源码中,都夹杂着模板模式的应用

定义

模板方法模式(Template Method Pattern):一个抽象类公开定义了执行它的方法的方式/模板。它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行。这种类型的设计模式属于行为型模式。

Define the skeleton of an algorithm in an operation,deferring some steps to subclasses.TemplateMethod lets subclasses redefine certain steps of an algorithm without changing the algorithm’sstructure(定义一个操作中的算法框架,而将一些步骤延迟到子类中,使得子类可以不改变一个算法的接口,即可重定义改算法的某些特定步骤)

模板方法模式是一种相对比较简单的模式,仅仅是使用了java的继承机制,但是它却是一种非常常见和常用的设计模式。

UML图示

【设计模式十三之模板方法模式】模板方法模式详解细说模板方法模式

从上图中可以看到,模板方法模式其实只有两个类型的类,一个试试抽象的模板类AbstractClass,还有一类是具体的实现类ConcreteClass类,继承自AbstractClass

抽象类(AbstractClass): 定义抽象的 原语操作(primitive operation) ,具体的子类将重定义它们以实现一个算法的各个步骤。实现一个模板方法,定义一个算法的骨架。该模板方法不仅调用原语操作,也调用定义在 AbstractClass 或其他对象中的操作

具体子类 (ConcreteClass): 实现原语操作以完成算法中与特定子类相关的步骤。

场景

场景一

实例来自设计模式之禅中,一个汽车在整个运行周期内,要经过上电启动,发动机响起,过程中可以按喇叭,停止这4个步骤,基本上这四个步骤其实都是固定下来的,那这个时候就可以创建一个汽车的模板方法模型,宝马车有这些行为,奔驰也有这些行为,所有的车都有这些相似,类似的行为。

场景二

某一天你想在家做饭了,你是不是要先去买菜,菜买回来之后要清理和洗菜,洗完之后要切菜,切菜之后要炒菜等菜炒好了之后需要把菜盛到碟子中。想一想,是不是基本上所有的做菜步骤都需要经过这些,那有人说,我可以不抄,有些我可以蒸的,那是啊,中间可以有一些判断形势决定你选择哪种方法去做菜啊。那这一系列的行为是不是也可以看成一个标准的模板行为。

上代码

代码一

定义一个模板方法抽象类HummerModel

package src.com.zzf.designpattern.teleplatemethodpattern.demo1;


public abstract class HummerModel {
	//车辆发动
	public abstract void start();
	//车辆停止
	public abstract void stop();
	//车辆喇叭响起
	public abstract void alarm();
	//发动起启动
	public abstract void engineBoom();
	//运行起来
	public abstract void run();
}

           

基于模板的实现类HummerH1Model

package src.com.zzf.designpattern.teleplatemethodpattern.demo1;


public class HummerH1Model extends HummerModel{

	@Override
	public void start() {
		// TODO Auto-generated method stub
		System.out.println("HummerH1Model start");
	}

	@Override
	public void stop() {
		// TODO Auto-generated method stub
		System.out.println("HummerH1Model stop");
	}

	@Override
	public void alarm() {
		// TODO Auto-generated method stub
		System.out.println("HummerH1Model alarm");
	}

	@Override
	public void engineBoom() {
		// TODO Auto-generated method stub
		System.out.println("HummerH1Model enginBoom");
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		this.start();
		this.engineBoom();
		this.alarm();
		this.stop();
	}

           

基于模板的实现类HummerH2Model

package src.com.zzf.designpattern.teleplatemethodpattern.demo1;


public class HummerH2Model extends HummerModel {

	@Override
	public void start() {
		// TODO Auto-generated method stub
		System.out.println("HummerH2Model start");
	}

	@Override
	public void stop() {
		// TODO Auto-generated method stub
		System.out.println("HummerH2Model stop");
	}

	@Override
	public void alarm() {
		// TODO Auto-generated method stub
		System.out.println("HummerH2Model alarm");
	}

	@Override
	public void engineBoom() {
		// TODO Auto-generated method stub
		System.out.println("HummerH2Model engineBoom");
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		this.start();
		this.alarm();
		this.engineBoom();
		this.stop();
	}

}
           

上述代码是不是模板方法模式??

当然是,抽象类中定义了一系列方法,但是上述其实是简单的继承而已,每个子类都需要实现一样的run方法,run方法中的执行的顺序也都是样的,所以需要对上述做一个优化。把run抽象到父类中。

重新定义一个模板,抽象类的方法改成protected,将直接在父类中定义好,并且加入final防止子类修改。同时添加了一个alarm方法。由子类决定是否是需要按喇叭

package src.com.zzf.designpattern.teleplatemethodpattern.demo1;



public abstract class HummerModel2 {
	//车辆发动
	protected abstract void start();  
	车辆停止
	protected abstract void stop();
	//车辆喇叭响起
	protected abstract void alarm();
	//发动机响起
	protected abstract void enginBoom();
	

	protected final void run(){  
		this.start();
		if(isAlarm()){
			this.alarm();
		}
		this.enginBoom();
		this.stop();
	}
	
	protected  boolean isAlarm(){
		return true;
	}
}

           

基于第二个模板的具体实现类,从中可以看出子类此时也就不需要在去实现run方法,而所有的子类其实在调用run方法时,所走的方法类型都是一样的

package src.com.zzf.designpattern.teleplatemethodpattern.demo1;


public class HummerH3Model2 extends HummerModel2{
	
	boolean isAlarm = false;
	
	@Override
	protected void start() {
		// TODO Auto-generated method stub
		System.out.println("HumemrH3Model2 start");
	}

	@Override
	protected void stop() {
		// TODO Auto-generated method stub
		System.out.println("HummerH3Model2 stop");
	}

	@Override
	protected void alarm() {
		// TODO Auto-generated method stub
		System.out.println("HummerH3Model2 alarm");
	}

	@Override
	protected void enginBoom() {
		// TODO Auto-generated method stub
		System.out.println("HummerH3Model2 enginBoom");
	}

	@Override
	protected boolean isAlarm() {
		// TODO Auto-generated method stub
		return isAlarm;
	}
	
	public void setAlarm(boolean isAlarm){
		this.isAlarm = isAlarm;
	}
	
}

           

测试代码

package src.com.zzf.designpattern.teleplatemethodpattern.demo1;


/**
 * 一个抽象类公开定义了执行它的方法的方式/模板。它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行。这种类型的设计模式属于行为型模式
	Define the skeleton of an algorithm in an operation,deferring some steps to subclasses.Template
	Method lets subclasses redefine certain steps of an algorithm without changing the algorithm's
	structure(定义一个操作中的算法框架,而将一些步骤延迟到子类中,使得子类可以不改变一个算法的接口,即可重定义改算法的某些特定步骤)
 */
public class TeleplateMethodPattern {
	public static void main(String[] args) {
		HummerModel mHummerModel = new HummerH1Model();
		mHummerModel.run();
		HummerH3Model2 mHummerModel2 = new HummerH3Model2();
		mHummerModel2.run();
	}
}
           

代码二

定义一个做饭的流程的模板类

package src.com.zzf.designpattern.teleplatemethodpattern.demo2;

public abstract class AbstractCook {
	
			
	//买菜
	protected abstract void buyVegetables();
	//洗菜
	protected abstract void washVegetables();
	//切菜
	protected abstract void cutVegetables();
	//炒菜
	protected  void firedVegetables(){};
	//蒸菜
	protected  void steamedVegetables(){};
	//盛菜
	protected abstract void servicedVegetables();
	
	public void cook() {
		this.buyVegetables();
		this.washVegetables();
		this.cutVegetables();
		int cookType = getCookType();
		if (cookType == 1) {
			this.firedVegetables(); 
		}else if (cookType == 2) {
			this.steamedVegetables(); 
		}else {
			System.out.println("错误的类型");
		}
		this.servicedVegetables();
	}
	
	
	public abstract int getCookType() ;
}

           

做鱼的流程

package src.com.zzf.designpattern.teleplatemethodpattern.demo2;

public class CookFish extends AbstractCook{

	@Override
	protected void buyVegetables() {
		// TODO Auto-generated method stub
		System.out.println("买鱼");
	}

	@Override
	protected void washVegetables() {
		// TODO Auto-generated method stub
		System.out.println("洗鱼");
	}

	@Override
	protected void cutVegetables() {
		// TODO Auto-generated method stub
		System.out.println("切鱼");
	}



	@Override
	protected void steamedVegetables() {
		// TODO Auto-generated method stub
		System.out.println("蒸鱼");
	}

	@Override
	protected void servicedVegetables() {
		// TODO Auto-generated method stub
		System.out.println("盛鱼");
	}

	@Override
	public int getCookType() {
		// TODO Auto-generated method stub
		return 2;
	}

}

           

做西红柿的具体流程

package src.com.zzf.designpattern.teleplatemethodpattern.demo2;

public class CookTomato extends AbstractCook{

	@Override
	protected void buyVegetables() {
		// TODO Auto-generated method stub
		System.out.println("买西红柿");
	}

	@Override
	protected void washVegetables() {
		// TODO Auto-generated method stub
		System.out.println("洗西红柿");
	}

	@Override
	protected void cutVegetables() {
		// TODO Auto-generated method stub
		System.out.println("切西红柿");
	}

	@Override
	protected void firedVegetables() {
		// TODO Auto-generated method stub
		System.out.println("炒西红柿");
	}

	@Override
	protected void servicedVegetables() {
		// TODO Auto-generated method stub
		System.out.println("盛西红柿");
	}

	@Override
	public int getCookType() {
		// TODO Auto-generated method stub
		return 1;
	}

}

           

测试代码

package src.com.zzf.designpattern.teleplatemethodpattern.demo2;

public class Test {
	public static void main(String[] args) {
		AbstractCook cook = new CookTomato();
		cook.cook();
		
		AbstractCook cooAbstractCook = new CookFish();
		cooAbstractCook.cook();
	}
}

           

基于UML的代码

package src.com.zzf.designpattern.teleplatemethodpattern.demo3;

public abstract class AbstractClass {
	protected abstract void primitiveOperation1();
	protected abstract void primitiveOperation2();
	public void templateMethod(){
		this.primitiveOperation1();
		this.primitiveOperation2();
	}
}

           
package src.com.zzf.designpattern.teleplatemethodpattern.demo3;

public class ConcreteClass1 extends AbstractClass {
	
	protected void primitiveOperation1() {
		// TODO Auto-generated method stub
		System.out.println("ConcreteClass1--->primitiveOperation1");
	}
	
	protected void primitiveOperation2() {
		System.out.println("ConcreteClass1--->primitiveOperation2");
	}
	
}

           
package src.com.zzf.designpattern.teleplatemethodpattern.demo3;

public class ConcreteClass2 extends AbstractClass{

	@Override
	protected void primitiveOperation1() {
		// TODO Auto-generated method stub
		System.out.println("ConcreteClass2--->primitiveOperation1");
	}

	@Override
	protected void primitiveOperation2() {
		// TODO Auto-generated method stub
		System.out.println("ConcreteClass2--->primitiveOperation2");
		
	}

}

           
package src.com.zzf.designpattern.teleplatemethodpattern.demo3;

public class Test {
	public static void main(String[] args) {
		AbstractClass abstractClass1 = new ConcreteClass1();
		abstractClass1.templateMethod();
		
		AbstractClass abstractClass2 = new ConcreteClass2();
		abstractClass2.templateMethod();
	}
}

           

模板方法模式使用和注意事项

模板方法是最常用的设计模式之一,其对封装不变的部分,扩展可变的部分,行为由父类去控制,然后子类去实现。

注意:

1:抽象模板中的基本方法尽量设计为protected类型,符合迪米特法则,不需要对外暴露属性或方法的尽量不需要去设置为public,

2:公共的模板方法类尽量设计成final类型,防止子类去修改其中方法的执行顺序

欢迎继续访问,我的博客