首页 > 代码库 > 04 - 模板方法模式
04 - 模板方法模式
模版模式: 又叫模板方法模式,在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情冴下,重新定义算法中的某些步骤。
模式中的角色:
抽象类(AbstractClass):实现了模板方法,定义了算法的骨架。
具体类(ConcreteClass):实现抽象类中的抽象方法,已完成完整的算法。
模式优缺点:
优点
- 模板方法模式通过把不变的行为搬移到超类,去除了子类中的重复代码。
- 子类实现算法的某些细节,有助于算法的扩展。
- 通过一个父类调用子类实现的操作,通过子类扩展增加新的行为,符合“开放-封闭原则”。
缺点
- 每个不同的实现都需要定义一个子类,这会导致类的个数的增加,设计更加抽象。
适用场景
- 在某些类的算法中,用了相同的方法,造成代码的重复。
- 控制子类扩展,子类必须遵守算法规则。
我们使用冲泡咖啡和冲泡茶的例子
加工流程:
咖啡冲泡法:1.把水煮沸、2.用沸水冲泡咖啡、3.把咖啡倒进杯子、4.加糖和牛奶
茶冲泡法: 1.把水煮沸、2.用沸水冲泡茶叶、3.把 茶 倒进杯子、4.加蜂蜜
实践步骤:
1>创建一个模板(抽象)类:Beverage(饮料)
package com.kaishengit.beverage; public abstract class Beverage { /** * 冲泡咖啡或茶...流程 */ public final void create(){ boilWater();//把水煮沸 brew();//用沸水冲泡... pourInCup();//把...倒进杯子 addCoundiments();//加... } public abstract void addCoundiments(); public abstract void brew(); public void boilWater() { System.out.println("煮开水"); } public void pourInCup() { System.out.println("倒进杯子"); } }
2>创建一个咖啡类(Coffee)和茶(Tea)类,都继承Beverage抽象类
1.咖啡(Coffee)
- package com.kaishengit.beverage;
- public class Coffee extends Beverage{
- @Override
- public void addCoundiments() {
- System.out.println("添加糖和牛奶"); }
- @Override
- public void brew() {
- System.out.println("用水冲咖啡");
- }
- }
2.茶(Tea)
Java代码
- package com.kaishengit.beverage;
- public class Tea extends Beverage{
- @Override
- public void addCoundiments() {
- System.out.println("添加蜂蜜");
- }
- @Override
- public void brew() {
- System.out.println("用水冲茶");
- }
- }
3.我们测试一下:
- package com.kaishengit.beverage;
- public class Test {
- public static void main(String[] args) {
- Coffee coffee = new Coffee();
- coffee.create();//冲泡咖啡
- //Tea tea = new Tea();//冲泡茶
- //tea.create();
- }
- }
运行结果:
-----------------------------------
煮开水
用水冲咖啡
倒进杯子
添加糖和牛奶
-----------------------------------
在模版模式中使用挂钩(hook)
存在一个空实现的方法,我们称这种方法为”hook”。子类可以视情况来决定是否要覆盖它。
1>我们对模板类(Beverage)进行修改
- package com.kaishengit.beverage;
- public abstract class Beverage {
- /**
- * 冲泡咖啡或茶...流程
- */
- public final void create(){
- boilWater();//把水煮沸
- brew();//用沸水冲泡...
- pourInCup();//把...倒进杯子
- addCoundiments();//加...
- hook();//挂钩
- }
- //空实现方法
- public void hook(){}
- public abstract void addCoundiments();
- public abstract void brew();
- public void boilWater() {
- System.out.println("煮开水");
- }
- public void pourInCup() {
- System.out.println("倒进杯子");
- }
- }
2>假如我们搞活动,喝一杯咖啡送一杯,修改咖啡(Coffee)类
- package com.kaishengit.beverage;
- public class Coffee extends Beverage{
- @Override
- public void addCoundiments() {
- System.out.println("添加糖和牛奶"); }
- @Override
- public void brew() {
- System.out.println("用水冲咖啡");
- }
- /**
- * 挂钩
- */
- @Override
- public void hook() {
- System.out.println("再来一杯");
- }
- }
3>使用上面的测试类
运行结果:
--------------------------------
煮开水
用水冲咖啡
倒进杯子
添加糖和牛奶
再来一杯
--------------------------------
结果中有“再来一杯”...
我们也可以这样使用挂钩,让其决定里面的代码是否执行
1>我们对模板类(Beverage)进行修改
- package com.kaishengit.beverage;
- public abstract class Beverage {
- /**
- * 冲泡咖啡或茶...流程
- */
- public final void create(){
- boilWater();//把水煮沸
- brew();//用沸水冲泡...
- pourInCup();//把...倒进杯子
- //挂钩决定是否添加配料
- if(hook()){
- addCoundiments();//加...
- }
- //hook();
- }
- /**
- * 默认添加配料
- * @return
- */
- public boolean hook() {
- return true;
- }
- //public void hook(){}
- public abstract void addCoundiments();
- public abstract void brew();
- public void boilWater() {
- System.out.println("煮开水");
- }
- public void pourInCup() {
- System.out.println("倒进杯子");
- }
- }
2>我们对Coffee类进行修改,让其不添加配料
- package com.kaishengit.beverage;
- public class Coffee extends Beverage{
- @Override
- public void addCoundiments() {
- System.out.println("添加糖和牛奶"); }
- @Override
- public void brew() {
- System.out.println("用水冲咖啡");
- }
- /**
- * 有的客人不喜欢加配料
- */
- @Override
- public boolean hook() {
- return false;
- }
- /*@Override
- public void hook() {
- System.out.println("再来一杯");
- }
- */
- }
3>还是使用上面的测试类
运行结果:
------------------------------------------------------
煮开水
用水冲咖啡
倒进杯子
------------------------------------------------------
运行结果中没有添加配料
关于模板模式
1>模板模式定义了算法的步骤,把这些步骤的实现延迟到子类
2>模板模式为我们提供了一个代码复用的技巧
3>模板抽象类中可以定义具体方法、抽象方法和钩子方法
4>为了防止子类改变模板中的算法,可以将模板方法声明为final
5>钩子是一种方法,它在抽象类中不做事,或只做默认的事,子类可以选择要不要实现它
-----------end--------------
3.2 模板方法模式代码实现
具体类,实现了抽象类中的特定步骤
}
3.3 客户端代码
运行结果
6. 模式举例: 用冒泡算法非别对整型数组、浮点数数组、日期数组实现排序。
6.1 实现类图
6.2 实现代码
///<summary>/// 抽象类,定义冒泡排序的骨架 ///</summary>publicabstractclass BubbleSorter { privateint operations = 0; protectedint length = 0; ///<summary>/// 冒泡排序算法 ///</summary>///<returns></returns>protectedint DoSort() { operations = 0; if (length <= 1) { return operations; } for (int nextToLast = length - 2; nextToLast >= 0; nextToLast--) { for (int index = 0; index <= nextToLast; index++) { if (OutOfOrder(index)) { Swap(index); } operations++; } } return operations; } ///<summary>/// 留给子类实现的交换位置方法 ///</summary>///<param name="index"></param>protectedabstractvoid Swap(int index); ///<summary>/// 留给子类实现的比较方法 ///</summary>///<param name="index"></param>///<returns></returns>protectedabstractbool OutOfOrder(int index); } ///<summary>/// 整型类型的冒泡算法实现 ///</summary>publicclass IntBubbleSorter:BubbleSorter { privateint[] array = null; ///<summary>/// 用冒泡算法排序 ///</summary>///<param name="theArray"></param>///<returns></returns>publicint Sort(int[] theArray) { array = theArray; length = array.Length; // 调用冒泡算法return DoSort(); } ///<summary>/// 实现冒泡算法中的交换操作 ///</summary>///<param name="index"></param>protectedoverridevoid Swap(int index) { int temp = array[index]; array[index] = array[index + 1]; array[index + 1] = temp; } ///<summary>/// 实现冒泡算法中的比较操作 ///</summary>///<param name="index"></param>///<returns></returns>protectedoverridebool OutOfOrder(int index) { return (array[index] > array[index + 1]); } } ///<summary>/// 浮点数类型的冒泡算法 ///</summary>publicclass FloatBubbleSorter:BubbleSorter { privatefloat[] array = null; ///<summary>/// 用冒泡算法排序 ///</summary>///<param name="theArray"></param>///<returns></returns>publicint Sort(float[] theArray) { array = theArray; length = array.Length; // 调用冒泡算法return DoSort(); } ///<summary>/// 实现冒泡算法中的交换操作 ///</summary>///<param name="index"></param>protectedoverridevoid Swap(int index) { float temp = array[index]; array[index] = array[index + 1]; array[index + 1] = temp; } ///<summary>/// 实现冒泡算法中的比较操作 ///</summary>///<param name="index"></param>///<returns></returns>protectedoverridebool OutOfOrder(int index) { return (array[index] > array[index + 1]); } }
6.3 客户端调用
class Program { staticvoid Main(string[] args) { // 对整型数组排序int[] intArray = newint[]{5, 3, 12, 8, 10}; BubbleSorter.IntBubbleSorter sorter = new BubbleSorter.IntBubbleSorter(); sorter.Sort(intArray); foreach (int item in intArray) { Console.Write(item+""); } Console.WriteLine(""); // 对浮点数排序float[] floatArray = newfloat[] { 5.0f, 3.0f, 12.0f, 8.0f, 10.0f }; BubbleSorter.FloatBubbleSorter floatSorter = new BubbleSorter.FloatBubbleSorter(); floatSorter.Sort(floatArray); foreach (float item in floatArray) { Console.Write(item + ""); } Console.Read(); } }
运行结果
04 - 模板方法模式