首页 > 代码库 > 设计模式之禅-模板方法模式

设计模式之禅-模板方法模式

个人Blog 此篇博文所在地址:http://www.sanyinchenblog.com/?p=273

模板方法模式:

定义一个操作中的算法框架,将一些步骤延迟到子类中。使得子类可以不改变    一个算法的结构即可重定义该算法的某些特定步骤。

Demo:

https://github.com/sanyinchen/UMLDemo/tree/master/src/com/sanyinchen/templete

https://github.com/sanyinchen/UMLDemo/tree/master/src/com/sanyinchen/templete2

介绍一下书上的背景,大概的背景是要做一个车的模型。

类图是这样的:




Client类:


package com.sanyinchen.templete;

public class Client {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		HummerModel hummerModel = new HummerH1Model1();
		hummerModel.start();
		hummerModel.engineBoom();
		hummerModel.alarm();
		hummerModel.run();
		System.out.println("--------------------");
		hummerModel = new HummerH1Model2();
		hummerModel.start();
		hummerModel.engineBoom();
		hummerModel.alarm();
		hummerModel.run();
	}

}

HummerModel:


public abstract class HummerModel {
	public abstract void start();

	public abstract void stop();

	public abstract void alarm();// 喇叭鸣叫

	public abstract void engineBoom();// 引擎发出轰鸣声

	public abstract void run();
}

HummerH1Model1

package com.sanyinchen.templete;

public class HummerH1Model1 extends HummerModel {

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

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

	@Override
	public void alarm() {
		// TODO Auto-generated method stub
		System.out.println("HummerH1Model1喇叭叫了");
	}

	@Override
	public void engineBoom() {
		// TODO Auto-generated method stub
		System.out.println("HummerH1Model1引擎启动了");
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		System.out.println("HummerH1Model1跑起来了");
		
	}

}

HummerH1Model2


public class HummerH1Model2 extends HummerModel {

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

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

	@Override
	public void alarm() {
		// TODO Auto-generated method stub
		System.out.println("HummerH1Model2喇叭叫了");
	}

	@Override
	public void engineBoom() {
		// TODO Auto-generated method stub
		System.out.println("HummerH1Model2引擎启动了");
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		System.out.println("HummerH1Model2跑起来了");
		
	}

}
程序运行的结构:



HummerH1Model1启动了
HummerH1Model1引擎启动了
HummerH1Model1喇叭叫了
HummerH1Model1跑起来了
--------------------
HummerH1Model2启动了
HummerH1Model2引擎启动了
HummerH1Model2喇叭叫了
HummerH1Model2跑起来了
当然,我们可以将每一步封装在run方法里:


HummerH1Model3:


package com.sanyinchen.templete;

public class HummerH1Model3 extends HummerModel {

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

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

	@Override
	public void alarm() {
		// TODO Auto-generated method stub
		System.out.println("HummerH1Model3喇叭叫了");
	}

	@Override
	public void engineBoom() {
		// TODO Auto-generated method stub
		System.out.println("HummerH1Model3引擎启动了");
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		this.start();
		this.engineBoom();
		this.alarm();
		System.out.println("HummerH1Model3跑起来了");
		
	}

}
这就是一个基本的模板设计模式,但是我们明显的可以看到会有重复代码,如果按照model3那个方式来,那么model4呢?run()里面的方法是一样的。


所以我们可以将HummerModel里的方法变为实现方法,所以在其他model继承的它的时候自然不需要再次实现它。

模板方法的优点:

(1)封装不变部分,扩展可变部分

(2)提取公共部分代码,便于维护

(3)行为由父类控制,子类实现

模板方法模式使用场景:

(1)多个子类有公有的方法,并且逻辑基本相同

(2)重要,复杂的代码,可以把核心算法设计为模板方法,周边相关细节功能则由各个子类实现

(3)重构时,模板方法模式是一个经常使用的模式,把相同的代码抽到父类中,然后通过钩子函数约束其行为。

模板方法的扩展:

下面需要修改一下需求,model1和model2的喇叭响不响是有控制的,因此添加一个钩子函数。

修改之后的类图:



Client

package com.sanyinchen.templete2;

/**
 * 模板方法模式 钩子函数使用
 * 
 * @author sanyinchen
 *
 */
public class Client {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		HummerModel hummerModel = new HummerH1Model1();
		hummerModel.run();
		System.out.println("--------------------");
		hummerModel = new HummerH1Model2();
		hummerModel.run();
		System.out.println("--------------------");
		HummerH1Model3 hummerMode3 = new HummerH1Model3();
		hummerMode3.steAram(false);
		hummerMode3.run();
	}

}

HummerModel:


package com.sanyinchen.templete2;

public abstract class HummerModel {
	public abstract void start();

	public abstract void stop();

	public abstract void alarm();// 喇叭鸣叫

	public abstract void engineBoom();// 引擎发出轰鸣声

	public abstract boolean isAlarm();

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

HummerH1Model3

package com.sanyinchen.templete2;

public class HummerH1Model3 extends HummerModel {

	private boolean isArm = true;

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

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

	@Override
	public void alarm() {
		// TODO Auto-generated method stub
		if(this.isAlarm())
		System.out.println("HummerH1Model3喇叭叫了");
	}

	@Override
	public void engineBoom() {
		// TODO Auto-generated method stub
		System.out.println("HummerH1Model3引擎启动了");
	}

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

	public void steAram(boolean flag) {
		this.isArm = flag;
	} }


运行结果:


HummerH1Model1启动了
HummerH1Model1引擎启动了
HummerH1Model1喇叭叫了
--------------------
HummerH1Model2启动了
HummerH1Model2引擎启动了
HummerH1Model2喇叭叫了
--------------------
HummerH1Model3启动了
HummerH1Model3引擎启动了


由此可以看出model3要不要响喇叭是由场景类决定的。



设计模式之禅-模板方法模式