细说模板方法模式
提示:
博主:章飞 _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类型,防止子类去修改其中方法的执行顺序
欢迎继续访问,我的博客