模板方法模式,定义一个操作中的算法的骨架,而将一些步骤移动(变动的部分)到子类中,模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
模板方法的关键点在于对重复代码的提炼(要精准)。模板方法就是提供了一个很好的代码复用平台。
以下给出模板方法模式的UML图:
以下给出模板方法模式的代码结构:
namespace ConsoleApplication1 { abstract class AbstractClass { public abstract void PrimitiveOperation1(); public abstract void PrimitiveOperation2(); //一些抽象行为 public void TemplateMethod() //模板方法,给出了逻辑的骨架,而逻辑的组成是一些相应的抽象操作,他们都推迟到子类实现 { PrimitiveOperation1(); PrimitiveOperation2(); Console.WriteLine(""); } } class ConcreteClassA : AbstractClass { public override void PrimitiveOperation1() { Console.WriteLine("具体类A的方法1实现"); //与ConcreteClassB不同的方法实现 } public override void PrimitiveOperation2() { Console.WriteLine("具体类A的方法2实现"); } } class ConcreteClassB : AbstractClass { public override void PrimitiveOperation1() { Console.WriteLine("具体类B的方法1实现"); //与ConcreteClassA不同的方法实现 } public override void PrimitiveOperation2() { Console.WriteLine("具体类B的方法2实现"); } } class Program { static void Main(string[] args) { AbstractClass c; c = new ConcreteClassA(); c.TemplateMethod(); c = new ConcreteClassB(); c.TemplateMethod(); Console.ReadKey(); } } }
以下给出《大话设计模式》里的两个简历例子,对比来看模板方法模式的好处。
以下为例子1:
namespace ConsoleApplication1 { //学生甲抄的试卷 class TestPaperA { //试题1 public void TestQuestion1() { Console.WriteLine("杨过得到,后来给了郭靖,炼成倚天剑、屠龙刀的玄铁可能是[ ] a、球磨铸铁 b、马口铁 c、高速合金钢 d、碳素纤维"); Console.WriteLine("答案:b"); } //试题2 public void TestQuestion2() { Console.WriteLine("杨过、程英、陆无双铲除了情花,造成[ ] a、使这种植物不在害人 b、使一种珍惜物种灭绝 c、破坏了生物圈平衡 d、造成该地区沙漠化"); Console.WriteLine("答案:a"); } //试题3 public void TestQuestion3() { Console.WriteLine("蓝凤凰致使华山师徒、陶谷六仙呕吐不止,如果你是大夫,会给他们开什么要[ ] a、阿司匹林 b、牛黄解毒片 c、感康 d、让他们喝大量的生牛奶 e、以上都不对"); Console.WriteLine("答案:c"); } } //学生乙抄的试卷 class TestPaperB { //试题1 public void TestQuestion1() { Console.WriteLine("杨过得到,后来给了郭靖,炼成倚天剑、屠龙刀的玄铁可能是[ ] a、球磨铸铁 b、马口铁 c、高速合金钢 d、碳素纤维"); Console.WriteLine("答案:d"); } //试题2 public void TestQuestion2() { Console.WriteLine("杨过、程英、陆无双铲除了情花,造成[ ] a、使这种植物不在害人 b、使一种珍惜物种灭绝 c、破坏了生物圈平衡 d、造成该地区沙漠化"); Console.WriteLine("答案:b"); } //试题3 public void TestQuestion3() { Console.WriteLine("蓝凤凰致使华山师徒、陶谷六仙呕吐不止,如果你是大夫,会给他们开什么要[ ] a、阿司匹林 b、牛黄解毒片 c、感康 d、让他们喝大量的生牛奶 e、以上都不对"); Console.WriteLine("答案:a"); } } class Program { static void Main(string[] args) { Console.WriteLine("学生甲抄的试卷:"); TestPaperA studentA = new TestPaperA(); studentA.TestQuestion1(); studentA.TestQuestion2(); studentA.TestQuestion3(); Console.WriteLine("学生乙抄的试卷:"); TestPaperB studentB = new TestPaperB(); studentB.TestQuestion1(); studentB.TestQuestion2(); studentB.TestQuestion3(); Console.ReadKey(); } } }
留意到以上大量的重复代码,复制粘贴这样的代码几乎是无法维护的。我也是这样写的,我操。
以下来看看模板方法模式的代码:
namespace ConsoleApplication1 { //金庸小说考题试卷 class TestPaper { public void TestQuestion1() { Console.WriteLine("杨过得到,后来给了郭靖,炼成倚天剑、屠龙刀的玄铁可能是[ ] a、球磨铸铁 b、马口铁 c、高速合金钢 d、碳素纤维"); Console.WriteLine("答案:" + Answer1()); } public void TestQuestion2() { Console.WriteLine("杨过、程英、陆无双铲除了情花,造成[ ] a、使这种植物不在害人 b、使一种珍惜物种灭绝 c、破坏了生物圈平衡 d、造成该地区沙漠化"); Console.WriteLine("答案:" + Answer2()); } public void TestQuestion3() { Console.WriteLine("蓝凤凰致使华山师徒、陶谷六仙呕吐不止,如果你是大夫,会给他们开什么要[ ] a、阿司匹林 b、牛黄解毒片 c、感康 d、让他们喝大量的生牛奶 e、以上都不对"); Console.WriteLine("答案:" + Answer3()); } protected virtual string Answer1() { return ""; } protected virtual string Answer2() { return ""; } protected virtual string Answer3() { return ""; } } //学生甲抄的试卷 class TestPaperA : TestPaper { protected override string Answer1() { return "b"; } protected override string Answer2() { return "c"; } protected override string Answer3() { return "a"; } } //学生乙抄的试卷 class TestPaperB : TestPaper { protected override string Answer1() { return "c"; } protected override string Answer2() { return "a"; } protected override string Answer3() { return "a"; } } class Program { static void Main(string[] args) { Console.WriteLine("学生甲抄的试卷:"); TestPaperA studentA = new TestPaperA(); studentA.TestQuestion1(); studentA.TestQuestion2(); studentA.TestQuestion3(); Console.WriteLine("学生乙抄的试卷:"); TestPaperB studentB = new TestPaperB(); studentB.TestQuestion1(); studentB.TestQuestion2(); studentB.TestQuestion3(); Console.ReadKey(); } } }
可以看到,提炼的非常厉害,可以说是完全没有复制的代码。这样的代码维护起来还是非常容易的。还是那一点,模板方法的关键在于提炼。