设计模式学习笔记(三):模板方法模式【Template Method】(三) 问题引申

 
  

    回顾下上面的这个模型,客户要关心的是模型的启动、停止、鸣笛和引擎声音。他只在run的过程中,听到或者看都成了啊,暴露那么多的方法干啥?

    那么,把抽象类上的四个方法设置为protected访问权限。既然客户不关心这几个方法,而且这四个方法都由子类来实现的,那就设置成protected模式。还有个缺陷,run方法既然子类都不修改,那是不是可以设置成final类型呢?答案是肯定的。

package com.example;

/**
 * 定义一个悍马的模型
 */
public abstract class HummerModel {

	//首先这个模型要发动
	protected abstract void start();
	//既然能发动就要能停下来
	protected abstract void stop();
	//要有喇叭
	protected abstract void alarm();
	//发动机的轰隆声
	protected abstract void engineBoom();
	//能跑动
	final public void run(){
		this.start();
		this.engineBoom();
		this.alarm();
		this.stop();
	}
}

    还有一个是叫做钩子方法,说明如下:

    假如有这么一个需求,喇叭响让它响就响。上面设计的例子,车子已启动喇叭就狂响,这就设计到钩子的方法:

package com.example;

/**
 * 定义一个悍马的模型
 */
public abstract class HummerModel {

	//首先这个模型要发动
	protected abstract void start();
	//既然能发动就要能停下来
	protected abstract void stop();
	//要有喇叭
	protected abstract void alarm();
	//发动机的轰隆声
	protected abstract void engineBoom();
	//能跑动
	final public void run(){
		this.start();
		this.engineBoom();
		
		//喇叭想让它响就响,不想让它响就不响
		if (this.isAlarm()) {
			this.alarm();
		}
		
		this.stop();
	}
	
	//钩子方法,默认喇叭是响的
	protected boolean isAlarm(){
		return true;
	}
}


      钩子方法模式是由抽象类来实现的,子类可以重写,H2型号的悍马是不会叫的,喇叭是个摆设。看HummerH2Model.java的代码:

package com.example;
/**
 * H2最接近民用系列
 */
public class HummerH2Model extends HummerModel{

	protected void start() {
		System.out.println("悍马H2发动...");
	}
	protected void stop() {
		System.out.println("悍马H2停止...");
	}
	protected void alarm() {
		System.out.println("悍马H2鸣笛...");
	}
	protected void engineBoom() {
		System.out.println("悍马H2引擎声音是这样的...");
	}
	
	//默认时没有喇叭
	protected boolean isAlarm(){
		return false;
	}
}


    H2型号的模型是没有喇叭的,就是按了喇叭也没有声音,那客户端这边的调用没有任何修改,出来的结果就不同。再来看下Client.java程序:

package com.example;

public class Client {

	public static void main(String[] args){
		
		//开着民用版的悍马遛弯
		HummerH2Model h2 = new HummerH2Model();
		h2.run();
	}
}

     运行出来的结果是这样的:

悍马H2发动...
悍马H2引擎声音是这样的...
悍马H2停止...

     那H1就有所不同了,它的喇叭要不要响是由客户来决定的。HummerH1Model.java的代码如下:

package com.example;
/**
 * H1最接近军用系列
 */
public class HummerH1Model extends HummerModel{
	private boolean alarmFlag = true;//是否要响喇叭
	
	protected void start() {
		System.out.println("悍马H1发动...");
	}
	protected void stop() {
		System.out.println("悍马H1停止...");
	}
	protected void alarm() {
		System.out.println("悍马H1鸣笛...");
	}
	protected void engineBoom() {
		System.out.println("悍马H1引擎声音是这样的...");
	}
	
	protected boolean isAlarm(){
		return this.alarmFlag;
	}
	public void setAlarm(boolean isAlarm){
		this.alarmFlag = isAlarm;
	}
}

     这段代码修改了两个地方,一是重写了父类的isAlarm()方法,一是增加了一个setAlarm方法,有调用者去决定是否要这个功能。再看下.Client.java的修改如下:

package com.example;

public class Client {

	public static void main(String[] args){
		//开着军用版的悍马遛弯
		HummerH1Model h1 = new HummerH1Model();
		h1.setAlarm(true);
		h1.run();
		
	}
}

     运行的结果如下:

悍马H1发动...
悍马H1引擎声音是这样的...
悍马H1鸣笛...
悍马H1停止...

   从上面的运行结果看到run起来就有声音了,那当然把h1.setAlarm(false)运行起来的来吧就没有声音了,钩子方法就是这样的。
   总结下:模板方法模式就是在模板方法中按照一个的过则和顺序调用基本方法,具体到上面的例子就是 run 方法按照规定的顺序(先调用 start,然后调用 engineBoom,再调用alarm,最后调用 stop)调用本类的其他方法,并且由 isAlarm 方法返回确定 run 中的执行顺序的变更。



 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值