模板方法模式——在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重写定义算法中的某些步骤。
假如我们有两种咖啡因饮料:茶和咖啡。茶的制作过程为:
(1)烧水
(2)用沸水浸泡茶叶
(3)把茶倒进杯子
(4)加柠檬
而咖啡的制作过程为:
(1)烧水
(2)用沸水冲泡咖啡
(3)把咖啡倒进杯子
(4)加糖和牛奶
我们发现两种饮料的制作有类似的过程:
(1)烧水
(2)用沸水泡咖啡或茶
(3)把饮料倒进杯子
(4)在饮料中加入适当调料
将(1)(3)在一个抽象基类——咖啡因饮料中定义和实现,而(2)(4)在基类中定义为抽象方法,交由具体的饮料子类去实现,并且基类提供一个方法按一定顺序调用这四个方法以完成饮料的制作。
抽象基类——咖啡因饮料
public abstract class CaffeineBeverage { public void prepareRecipe() { boilWater(); brew(); pourInCup(); if (customerWantsCondiments()) { addCondiments(); } } protected abstract void brew(); protected abstract void addCondiments(); void boilWater() { Console.WriteLine("Boiling water"); } void pourInCup() { Console.WriteLine("Pouring in cup"); } protected virtual bool customerWantsCondiments()//钩子 { return true; } }
茶
class Tea : CaffeineBeverage { protected override void brew() { Console.WriteLine("Steeping in tea"); } protected override void addCondiments() { Console.WriteLine("Adding lemon"); } }
咖啡
class Coffee : CaffeineBeverage { protected override void brew() { Console.WriteLine("Dripping Coffee through filter"); } protected override void addCondiments() { Console.WriteLine("Adding Sugar and Milk"); } }
还可以在基类中定义钩子方法,该方法通过空的或者默认的实现,子类可有以选择性的覆盖该方法。钩子方法可以用于影响抽象基类的算法流程。
带有钩子的咖啡:钩子用于控制是否加入调料
class CoffeeWithHook : CaffeineBeverage { override protected void brew() { Console.WriteLine("Dripping Coffee through filter"); } override protected void addCondiments() { Console.WriteLine("Adding Sugar and Milk"); } protected override bool customerWantsCondiments() { string answer = getUserInput(); if (answer.ToLower().StartsWith("y")) { return true; } else { return false; } } private string getUserInput() { string answer = null; Console.WriteLine("Would you like milk and sugar with your coffee(y/n)?"); try { answer = Console.ReadLine(); } catch (System.Exception ex) { Console.WriteLine("IO error trtying to read your answer"); } if (answer==null) { return "no"; } return answer; } }
class Program { static void Main(string[] args) { Tea myTea = new Tea(); Coffee myCoffee = new Coffee(); CoffeeWithHook CoffeeHook = new CoffeeWithHook(); myTea.prepareRecipe(); Console.WriteLine(""); myCoffee.prepareRecipe(); Console.WriteLine(""); CoffeeHook.prepareRecipe(); Console.ReadKey(); } }