概念:
定义一个操作中算法的框架,而将一些步骤延迟到子类中。模板方法模式使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
通俗点就是 说在父类中定义一些通用方法,然后其他一些独特方法交给子类去实现。(前提是该场景适用模板模式)
如下:
在软件开发中,有时也会遇到类似的情况,某个方法的实现需要多个步骤(类似“请客”),**其中有些步骤是固定的(类似“点单”和“买单”),而有些步骤并不固定,存在可变性(类似“吃东西”)。为了提高代码的复用性和系统的灵活性,可以使用一种称之为模板方法模式的设计模式来对这类情况进行设计,在模板方法模式中,将实现功能的每一个步骤所对应的方法称为基本方法(例如“点单”、“吃东西”和“买单”),而调用这些基本方法同时定义基本方法的执行次序的方法称为模板方法(例如“请客”)。**在模板方法模式中,可以将相同的代码放在父类中,例如将模板方法“请客”以及基本方法“点单”和“买单”的实现放在父类中,而对于基本方法“吃东西”,在父类中只做一个声明,将其具体实现放在不同的子类中,在一个子类中提供“吃面条”的实现,而另一个子类提供“吃满汉全席”的实现。通过使用模板方法模式,一方面提高了代码的复用性,另一方面还可以利用面向对象的多态性,在运行时选择一种具体子类,实现完整的“请客”方法,提高系统的灵活性和可扩展性。
demo:
某软件公司欲为某银行的业务支撑系统开发一个利息计算模块,利息计算流程如下:
(1) 系统根据账号和密码验证用户信息,如果用户信息错误,系统显示出错提示;
(2) 如果用户信息正确,则根据用户类型的不同使用不同的利息计算公式计算利息(如活期账户和定期账户具有不同的利息计算公式);
(3) 系统显示利息。
试使用模板方法模式设计该利息计算模块。
//Account.cs
using System;
//1.抽象类
namespace TemplateMethodSample
{
abstract class Account
{
//基本方法——具体方法
public bool Validate(string account, string password)
{
Console.WriteLine("账号:{0}", account);
Console.WriteLine("密码:{0}", password);
//模拟登录
if (account.Equals("张无忌") && password.Equals("123456"))
{
return true;
}
else
{
return false;
}
}
//基本方法——抽象方法
public abstract void CalculateInterest();
//基本方法——具体方法
public void Display()
{
Console.WriteLine("显示利息!");
}
//模板方法
public void Handle(string account, string password)
{
if (!Validate(account,password))
{
Console.WriteLine("账户或密码错误!");
return;
}
CalculateInterest();
Display();
}
}
}//CurrentAccount.cs
using System;
//2.CurrentAccount:活期账户类,充当具体子类。
namespace TemplateMethodSample
{
class CurrentAccount : Account
{
//覆盖父类的抽象基本方法
public override void CalculateInterest()
{
Console.WriteLine("按活期利率计算利息!");
}
}
}//SavingAccount.cs
using System;
//3.SavingAccount:定期账户类,充当具体子类。
namespace TemplateMethodSample
{
class SavingAccount : Account
{
//覆盖父类的抽象基本方法
public override void CalculateInterest()
{
Console.WriteLine("按定期利率计算利息!");
}
}
}
//4.Program:客户端测试类
//Program.cs
using System;
using System.Configuration;
using System.Reflection;
namespace TemplateMethodSample
{
class Program
{
static void Main(string[] args)
{
Account account;
//读取配置文件
string subClassStr = ConfigurationManager.AppSettings["subClass"];
//反射生成对象
account = (Account)Assembly.Load("TemplateMethodSample").CreateInstance(subClassStr);
account.Handle("张无忌", "123456");
Console.Read();
}
}
}