在软件开发的过程中,如果相同的一段代码复制过两次,就需要对设计产生怀疑。
我们把相同的代码提取出来,提供一个模板,这就叫模板方法模式
看一个例子:
这个例子是悍马车的设计,首先定义几个悍马车的接口
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();
}
}