设计模式(4):模板方法模式
模板方法模式:
定义:
定义一个操作中的算法框架,而将一些步骤延迟到子类中。
使得子类能够不改变一个算法的结构就可以重定义该算法的某些特定步骤。
模板方法模式很easy,只使用了Java的继承机制,但它是一个应用很广泛的模式。
在软件开发project中,假设同样一段代码复制过两次,就须要对设计产生怀疑。架构师要明白地说明为什么同样的逻辑要出现两次或很多其它次。
模板方法模式的长处:
封装不变。扩展可变部分
提取公共部分代码。便于维护
行为有父类控制,子类实现。
缺点:
子类对父类产生了影响。
生产悍马车辆模型:
类图:
悍马车有两个型号:H1和H2。
抽象悍马接口:
abstract class HummerModel { // 启动 public abstract void start(); // 停下 public abstract void stop(); // 喇叭响 public abstract void alarm(); // 发动机响 public abstract void engineBoom(); // 跑起来 public abstract void run(); }
两种类型的悍马:
// H1悍马模型 class HummerH1Model extends HummerModel { public void start() { System.out.println("启动起来了"); } public void stop() { System.out.println("停下来了"); } public void alarm() { System.out.println("喇叭响了"); } public void engineBoom() { System.out.println("发动机发动"); } public void run() { // 先发动汽车 this.start(); // 引擎发动 this.engineBoom(); // 喇叭响 this.alarm(); // 停车 this.stop(); } } // H2类型 class HummerH2Model extends HummerModel { public void start() { System.out.println("启动起来了"); } public void stop() { System.out.println("停下来了"); } public void alarm() { System.out.println("喇叭响了"); } public void engineBoom() { System.out.println("发动机发动"); } public void run() { // 先发动汽车 this.start(); // 引擎发动 this.engineBoom(); // 喇叭响 this.alarm(); // 停车 this.stop(); } }
两个实现类中run方法中的代码是同样的,这个run方法的实现应该在抽象类中,而不是在实现类中。
改动之后是这种:
abstract class HummerModel { // 启动 public abstract void start(); // 停下 public abstract void stop(); // 喇叭响 public abstract void alarm(); // 发动机响 public abstract void engineBoom(); // 跑起来 public void run() { // 先发动汽车 this.start(); // 引擎发动 this.engineBoom(); // 喇叭响 this.alarm(); // 停车 this.stop(); } } // H1悍马模型 class HummerH1Model extends HummerModel { public void start() { System.out.println("悍马H1---->启动起来了"); } public void stop() { System.out.println("悍马H1---->停下来了"); } public void alarm() { System.out.println("悍马H1---->喇叭响了"); } public void engineBoom() { System.out.println("悍马H1---->发动机发动"); } } // H2类型 class HummerH2Model extends HummerModel { public void start() { System.out.println("悍马H2---->启动起来了"); } public void stop() { System.out.println("悍马H2---->停下来了"); } public void alarm() { System.out.println("悍马H2---->喇叭响了"); } public void engineBoom() { System.out.println("悍马H2---->发动机发动"); } }
这时抽象类HummerModel类中的run方法叫做模板方法,其它的方法叫做基本方法。模板方法实现对基本方法的调度。完毕固定的业务逻辑。
场景类:
public class Client { public static void main(String[] args) { HummerModel h1 = new HummerH1Model(); h1.run(); HummerModel h2 = new HummerH2Model(); h2.run(); } }
抽象模板类中的基本方法尽量设计为protected类型。符合迪米特法则,实现类若非必要尽量不要扩大父类中的訪问权限。
模板方法模式的扩展:
H1型号的悍马喇叭想让它响就响,H2型号的喇叭不要有声音。
在抽象类中添加一个实现方法isAlarm,有各个类覆写该方法。
abstract class HummerModel { // 启动 protected abstract void start(); // 停下 protected abstract void stop(); // 喇叭响 protected abstract void alarm(); // 发动机响 protected abstract void engineBoom(); // 跑起来 public void run() { // 先发动汽车 this.start(); // 引擎发动 this.engineBoom(); // 喇叭响 if (this.isAlarm()) { this.alarm(); } // 停车 this.stop(); } // 钩子方法,默认喇叭是会响的 protected boolean isAlarm() { return true; } } // H1悍马模型 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 alarmFlag) { this.alarmFlag = alarmFlag; } } // H2类型 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; } }
场景类:
public class Client { public static void main(String[] args) throws IOException { HummerModel h1 = new HummerH1Model(); System.out.println("-------------H1型号悍马---------------"); System.out.println("H1型号的悍马是否须要喇叭响? 0-不须要 1-须要"); String type = (new BufferedReader(new InputStreamReader(System.in))).readLine(); if(type.equals("0")){ ((HummerH1Model) h1).setAlarm(false); } h1.run(); System.out.println("-------H2型号的悍马----"); HummerModel h2 = new HummerH2Model(); h2.run(); } }
用户能够控制H1型号的车的喇叭。外界条件改变,影响到了模板方法的运行。
抽象类中的isAlarm方法叫做钩子方法。
有钩子方法的模板方法模式才算完美。