行为型设计模式。
在现实生活中,很多事情都包含几个实现步骤,例如请客吃饭,无论吃什么,一般都包含点单,吃东西,买单等几个步骤,通常情况下这几个步骤的次序是:点单——》吃东西——》买单。在这三个步骤中,点单和买单大同小异,最大的区别在于第二步——吃什么,吃面条还是吃满汉全席可是大不相同的。
在软件开发中,开发人员有时也会遇到类似的情况,某个方法的实现需要多个步骤,其中有些步骤是固定的,有些则是不固定的,存在可变性。为了提高代码的可用性和系统的灵活性,可以使用一种称为模板方法模式的设计模式来对这种情况进行设计。在模板方法中将实现功能的每一个方法称为基本方法,而调用这些基本方法并决定其执行次序的方法被称为模板方法。我们可以将相同的代码放在父类,而变化的代码则有子类实现,这样就可以解决上面吃什么的问题了。
由上图可知,模板方法模式由以下2个角色构成。
AbstractClass(抽象父类):
在抽象类中会定义一系列的基本操作,这些操作可以是具体的也可以是抽象的,每一个方法都对应了算法步骤中的一步,在其子类中可以重定义火实现这些步骤。同时,在抽象类中实现了一个模板方法,用于定义一个算法的框架。
ConcreteClass(具体子类):
是抽象类的子类,用于在子类中实现父类中声明的抽象基本操作,及完成子类特定算法的步骤,也可以覆盖在父类中已经实现的具体基本操作。
例子:某软件公司要为某银行的业务支撑系统开发一个利息计算模块,计算流程如下:
试使用模板方法模式模拟此系统。
Account类:
using System; namespace TemplateMethod.TemplateMethod.Example { public abstract class Account { public string Name { get; set; } public string Password { get; set; } public Account(string name, string password) { Name = name; Password = password; } /// <summary> /// 模板方法 /// </summary> /// <param name="name"></param> /// <param name="password"></param> public void Execute(string name, string password) { if (Check(name, password)) { Console.WriteLine(Calculate()); } else { Console.WriteLine($"错误"); } } public bool Check(string name, string password) { if (Name.Equals(name) && Password.Equals(password)) { return true; } else { return false; } } public abstract float Calculate(); } }
SavingAccount类:
namespace TemplateMethod.TemplateMethod.Example { public class SavingAccount : Account { public SavingAccount(string name, string password) : base(name, password) { } public override float Calculate() { return 1f; } } }
CurrentAccount类:
namespace TemplateMethod.TemplateMethod.Example { public class CurrentAccount : Account { public CurrentAccount(string name, string password) : base(name, password) { } public override float Calculate() { return 0f; } } }
Program类:
using TemplateMethod.TemplateMethod.Example; namespace TemplateMethod { internal class Program { public static void Main(string[] args) { Account xiaoming = new CurrentAccount("xiaoming", "123456"); xiaoming.Execute("xiaoming", "123456"); xiaoming.Execute("123","123"); Account xiaohong = new SavingAccount("xiaohong", "123456"); xiaohong.Execute("xiaohong", "123456"); xiaohong.Execute("123","123"); } } }