由于前两天刚好用到模板方法这个模式,而且这个模式相对来 比较简单实用,就写写个人的一些认知吧!
大家对宋丹丹和赵本山的小品里有一个很经典的台词一定不会陌生,而且还日常中经常引用:
《钟点工》中宋丹丹问要把大象装冰箱,总共分几步?赵本山就懵了,大象那么大,冰箱那么小,怎么才能把大象装冰箱里呢?
答案也很经典:三步:第1步,把冰箱门打开;第2步,把大象装进去;第3步,把冰箱门带上。
这个小品名字可能没多少人还记得,但是这个故事我想看过的人都会记得吧。那么从软件设计的角度如何看上面的问题呢?其实管他是大象,小象任何东西,只要是向冰箱里面放,最后抽象出来就三步而已,就是答案给出的三步第1步,把冰箱门打开;第2步,把大象装进去;第3步,把冰箱门带上。是不是呢?
用代码看是不是这样,任何东西Anything都会有这三步
public abstract class Anything { /// <summary> ///第一步 打开冰箱 /// </summary> protected abstract void OPenFridge(); /// <summary> /// 第二步 大象放进冰箱 /// </summary> protected abstract void PutIntoFridge(); /// <summary> /// 第三步 关上冰箱 /// </summary> protected abstract void CloseFridge(); }
抽象类Anything类现在是只有三个抽象的方法对应上面的三步,接下来是不是还少一个总的对外方法,来封装现有的这三步呢?
public abstract class Anything { protected Anything() { } /// <summary> /// 装进冰箱 /// </summary> public void Put() { OPenFridge(); PutIntoFridge(); CloseFridge(); } /// <summary> ///第一步 打开冰箱 /// </summary> protected abstract void OPenFridge(); /// <summary> /// 第二步 大象放进冰箱 /// </summary> protected abstract void PutIntoFridge(); /// <summary> /// 第三步 关上冰箱 /// </summary> protected abstract void CloseFridge(); }
可能已经注意到这里是把OPenFridge(),PutIntoFridge(), CloseFridge()三个方法都是protected 的抽象方法,原因是:
- protected· 对外是不开放的,只对子类可见。由于实际要把东西放进冰箱里,只要调用Put()方法,不可能调用OpenFridge()
- abstract 具体的实现要到具体的类中去实现。可能实际中这三个抽象方法,只有PutIntoFridge()是不相同的,打开冰箱与关上冰箱是相同的,那么就这可在Anything中实现,而且可以把这两个方法改为private,具体的对象只用实现PutIntoFridge()就可以了。
好接下来我们看要把大象,鸡蛋放进冰箱李,大象,鸡蛋该怎么实现:
/// <summary> /// 大象 /// </summary> public class Elephant:Anything { protected override void OPenFridge() { Console.WriteLine("要放大象了,先打开冰箱门!"); } protected override void PutIntoFridge() { Console.WriteLine("把大象大卸八块放进冰箱的冷藏室!"); } protected override void CloseFridge() { Console.WriteLine("大象放进冰箱了,可以关上门了!"); } }
/// <summary> ///鸡蛋 /// </summary> public class Egg : Anything { protected override void OPenFridge() { Console.WriteLine("要放鸡蛋了,先打开冰箱门!"); } protected override void PutIntoFridge() { Console.WriteLine("把鸡蛋放进冰箱的保鲜室!"); } protected override void CloseFridge() { Console.WriteLine("鸡蛋放进冰箱了,可以关上门了!"); } }
最后再看看客户端怎么调用:
static void Main() { //鸡蛋 Anything egg=new Egg(); //大象 Anything elephant = new Elephant(); //鸡蛋放进冰箱 egg.Put(); //大象放进冰箱 elephant.Put(); }
上面例子用到的就是模板方法 (Template Method)——定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。Template Method使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
由于该模式的UML图相对比较简单,就省掉了,直接运用vs的反向工程工具导出类图看看吧!
该模式常用在一些处理的步骤、流程或骨架固定不变——父类中定义实现,但是具体实现步骤不同——延迟至子类中实现。
ps: 一般我们常知道的是子类可以调用父类的方法,在该模式中提供了一种父类调用子类的方法的方式。