模板方法模式

在软件开发的过程中,如果相同的一段代码复制过两次,就需要对设计产生怀疑。

我们把相同的代码提取出来,提供一个模板,这就叫模板方法模式

看一个例子:

这个例子是悍马车的设计,首先定义几个悍马车的接口

package com.feng.model;

public abstract class HummerModel {

	public abstract void start();
	public abstract void stop();
	public abstract void alarm();
	public abstract void enginBoom();
	public abstract void run();
}
现在有HummerH1和HummerH2两种模型的悍马来实现这个接口

package com.feng.model;

public class HummerH1Model extends HummerModel{

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

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

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

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

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

}
package com.feng.model;

public class HummerH2Model extends HummerModel{

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

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

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

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

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

}
看到这里,我们会发现,在两个实现类中的run方法中的代码是完全一样的,对于这种现象,是不是说明我们设计的不是很完美,我们完全可以把这个方法提取到顶层的抽象类中,修改如下:

Hummer抽象类:

package com.feng.model;

public abstract class HummerModel {

	protected abstract void start();
	protected abstract void stop();
	protected abstract void alarm();
	protected abstract void enginBoom();
	public void run()
	{
		this.start();
		this.enginBoom();
		this.alarm();
		this.stop();
	}
}
两个实现类:

package com.feng.model;

public class HummerH1Model extends HummerModel{

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

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

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

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

}
package com.feng.model;

public class HummerH2Model extends HummerModel{

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

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

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

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

}
测试类:

package com.feng.model;

public class Test {

	public static void main(String[] args)
	{
		HummerModel hummer = new HummerH1Model();
		hummer.run();
	}
}
注意地点,对于run方法其他的类,我们可以声明为protected类型,这样可以起到封装保护的作用。

其次,run方法我们还可以定义为final类型,不允许复写。

模板方法模式的优点:

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

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

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

模板方法模式的缺点:

模板方法模式中抽象类定义了部分抽象方法,由子类实现,子类执行结果影响父类的结果。对代码的阅读会带来不便。
模板方法的扩展:

需求总是会变的,如果现在客户要求H1型号的Hummer喇叭想让他想它就响。H2型号的喇叭不要有声音,那怎么改

我们可以在抽象类中加一个方法,这个方法来判断用户要不要车响喇叭。

代码修改如下:

package com.feng.model;

public abstract class HummerModel {

	protected abstract void start();
	protected abstract void stop();
	protected abstract void alarm();
	protected abstract void enginBoom();
	
	//钩子方法,默认喇叭是会响的
	protected boolean isAlarm()
	{
		return true;
	}
	public void run()
	{
		this.start();
		this.enginBoom();
		if(isAlarm())
		{
			this.alarm();
		}
		this.stop();
	}
}
两个车型的实现:

package com.feng.model;

public class HummerH1Model extends HummerModel{

	private boolean alarmFlag = true;
	@Override
	protected void start() {
		// TODO Auto-generated method stub
		System.out.println("Hummer H1 start...");
		
	}

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

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

	@Override
	protected void enginBoom() {
		// TODO Auto-generated method stub
		System.out.println("Hummer H1 enginBoom...");
		
	}
	
	protected boolean isAlarm()
	{
		return this.alarmFlag;
	}
	
	//还要给用户提供一个接口,让用户去设置喇叭应不应该响
	public void setAlarm(boolean alarmFlag)
	{
		this.alarmFlag = alarmFlag;
	}

}
package com.feng.model;

public class HummerH2Model extends HummerModel{

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

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

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

	@Override
	protected void enginBoom() {
		// TODO Auto-generated method stub
		System.out.println("Hummer H2 enginBoom...");
	}
	
	//这个模型的车子永远都不会响喇叭,所以返回false就可以了
	protected boolean isAlarm()
	{
		return false;
	}

}
测试类:

package com.feng.model;

public class Test {

	public static void main(String[] args)
	{
		HummerModel hummer = new HummerH1Model();
		hummer.run();
		
		//但是在这想要调用HummerH1Model,必须要构造具体的子类对象才能调用setAlarm()方法
		System.out.println("=================");
		HummerH1Model h1 = new HummerH1Model();
		h1.setAlarm(false);
		h1.run();
		
		System.out.println("=================");
		hummer = new HummerH2Model();
		hummer.run();
	}
}








你可能感兴趣的:(设计模式,模板方法模式)