1:主题拆解
①基本介绍
②银行系统存款模拟
③模板方法模式的优缺点
④适用场景
⑤MVC框架使用
⑥知识扩展
2:基本介绍
模板方法模式:简单、强大、无所不在,框架搭建必备。
模板方法:定义通用处理流程;实现了通用部分;可变部分留作扩展点。
框架搭建:定义业务处理流程;实现了通用部分;可变部分留作扩展点。
模板方法模式,在一个抽象类公开定义了执行它的方法的模板。它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行。
简单说,就是定义一个操作的算法骨架,而将一些步骤延迟到子类中,使得子类可以不改变一个算法的结构就可以重新定义该算法的某些步骤。
3:银行系统存款模拟
本次模拟的场景为用户到银行系统中存钱。
①银行存折基类
public abstract class BaseClient
{
/// <summary>
/// 登陆查询功能
/// </summary>
/// <param name="id"></param>
/// <param name="name"></param>
/// <param name="password"></param>
public void Query(int id, string name, string password)
{
if (this.CheckUser(id, password))
{
double balance = this.QueryBalance(id);
double interest = this.CalculateInterest(balance);
this.Show(name, balance, interest);
}
else
{
Console.WriteLine("账户密码错误");
}
}
/// <summary>
/// 用户检测
/// </summary>
/// <param name="id"></param>
/// <param name="password"></param>
/// <returns></returns>
public bool CheckUser(int id, string password)
{
return DateTime.Now < DateTime.Now.AddDays(1);
}
/// <summary>
/// 查询余额
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public double QueryBalance(int id)
{
return new Random().Next(10000, 1000000);
}
/// <summary>
/// 获取利率,计算利息
/// </summary>
/// <param name="balance"></param>
/// <returns></returns>
public abstract double CalculateInterest(double balance);
/// <summary>
/// 展示下余额和利息
/// </summary>
/// <param name="name"></param>
/// <param name="balance"></param>
/// <param name="interest"></param>
public virtual void Show(string name, double balance, double interest)
{
Console.WriteLine("尊敬的{0}客户,你的账户余额为:{1},利息为{2}",
name, balance, interest);
}
}
②活期用户存钱,需要将计算利息的方法重写
public class ClientCurrent: BaseClient
{
public override double CalculateInterest(double balance)
{
return balance * 0.03;
}
}
③定期用户存在,由于计算利息不一样
public class ClientRegular : BaseClient
{
public override double CalculateInterest(double balance)
{
return balance * 0.05;
}
}
④VIP用户,可能不仅仅是利息不一样,提供的服务或许也不一样
public class ClientVip : BaseClient
{
public override double CalculateInterest(double balance)
{
return balance * 0.07;
}
public override void Show(string name, double balance, double interest)
{
Console.WriteLine("尊贵的{0}客户,你的账户余额为:{1},利息为{2}",
name, balance, interest);
Console.WriteLine("理财有风险,入行需谨慎");
}
}
⑤三个用户存取调用
Console.WriteLine("****************ClientCurrent****************");
BaseClient current = new ClientCurrent();
current.Query(234, "活期", "123");
Console.WriteLine("****************ClientCurrent****************");
BaseClient regular = new ClientRegular();
regular.Query(345, "定期", "456");
Console.WriteLine("****************ClientVip****************");
BaseClient vip = new ClientVip();
vip.Query(345, "VIP", "789");
分析:用户基类中BaseClient中有三种方法。
普通方法:登陆,检查,余额查询。这三个方法是完全通用的,因此在基类中实现,子类直接继承使用即可。
抽象方法:计算利息。由于活期用户,定期用户,VIP用户对利息的计算规则不一样,因此在基类中定义为抽象方法,子类继承后可以对于不用的要求进行重写。
虚方法:展示余额和利息。由于大部分用户的展示方法是相同的,只有很少一部分特殊的用户才需要进行个性化定制。此时在基类中定义为虚方法。子类继承后,可以直接使用,如果遇到需要个性化定制,只用按照需求重写即可。
4:模板方法模式的优缺点
1:优点
①形式化算法
模板方法模式在父类中形式化地定义一个算法,而由子类来实现细节的处理,在子类实现详细的处理算法时并不会改变算法中步骤的执行次序。
②代码复用
模板方法模式是一种代码复用技术,提取公共行为并放在父类中,通过子类实现不同的行为。
③实现反向控制
模板方法模式可实现一种反向控制结构,通过子类覆盖父类的钩子方法来决定某一特定步骤是否执行。
④增加子类方便
模板方法模式中可通过子类覆盖父类的基本方法,不同子类可以提供基本方法的不同实现,更换以及增加新的子类很方便。
2:缺点
①子类数量多
模板方法模式需要为每一个基本方法的不同实现提供一个子类,如果父类可变的基本方法太多,将会导致类的个数增加,系统更加庞大,设计也更加抽象。
5:适用场景
①多个子类有共有的方法,并且逻辑基本相同。
②重要、复杂的算法,可以把核心算法设计为模板方法,周边的相关细节功能则由各个子类实现。
③重构时,模板方法是一个经常使用的方法,把相同的代码抽取到父类中,然后通过构造函数约束其行为。
6:MVC框架使用
如上图所示,MVC控件中就是采用的模版方法模式,提供模式的实现,同事也预留了扩展点,用户可以自定义进行定制。
7:知识扩展
1:抽象方法-执行结果?
public abstract class ParentClass
{
public abstract void Show();
}
public class ChildClass : ParentClass
{
public override void Show()
{
Console.WriteLine("This is ChildClass");
}
}
ParentClass abstractTest1 = new ChildClass();
abstractTest1.Show();
ChildClass abstractTest2 = new ChildClass();
abstractTest2.Show();
分析:抽象类不能直接实例化,也不包括实现。子类继承并且对其进行了实现,因此都是调用子类方法。
2:普通方法-执行结果?
public class NewTest
{
public void Show()
{
Console.WriteLine("This is NewTest");
}
}
public class NewTestChild : NewTest
{
public new void Show()
{
Console.WriteLine("This is NewTestChild");
}
}
NewTest newTest1 = new NewTest();
newTest1.Show();
NewTest newTest2 = new NewTestChild();
newTest2.Show();
分析:普通方法的调用,编译时决定的,左边决定的。因此都是调用的父类。可以留意到自恋隐藏父类方法的时候,new 要不要都没区别,都会隐藏。
3:虚方法-执行结果?
public class VirtualTest
{
public virtual void Show()
{
Console.WriteLine("This is VirtualTest");
}
}
public class VirtualTestChild : VirtualTest
{
public override void Show()
{
Console.WriteLine("This is VirtualTestChild");
}
}
VirtualTest virtualTest1 = new VirtualTest();
VirtualTest virtualTest2 = new VirtualTestChild();
VirtualTestChild virtualTest3 = new VirtualTestChild();
virtualTest1.Show();
virtualTest2.Show();
virtualTest3.Show();
分析:抽象/虚 方法的调用,运行时决定的,右边决定的。
虚方法,必须包含实现,但是可以被覆写。