模板方法模式深度解析(二)

3 模板方法模式应用实例

下面通过一个应用实例来进一步学习和理解模板方法模式。

  1. 实例说明

某软件公司欲为某银行的业务支撑系统开发一个利息计算模块,利息计算流程如下:

(1) 系统根据账号和密码验证用户信息,如果用户信息错误,系统显示出错提示;

(2) 如果用户信息正确,则根据用户类型的不同使用不同的利息计算公式计算利息(如活期账户和定期账户具有不同的利息计算公式);

(3) 系统显示利息。

试使用模板方法模式设计该利息计算模块。

  1. 实例类图

通过分析,本实例结构图如图3所示。

模板方法模式深度解析(二) - 图1

图3 银行利息计算模块结构图

在图3中,Account充当抽象类角色,CurrentAccount和SavingAccount充当具体子类角色。

  1. 实例代码

(1) Account:账户类,充当抽象类。

  1. //Account.cs
  2. using System;
  3. namespace TemplateMethodSample
  4. {
  5. abstract class Account
  6. {
  7. //基本方法——具体方法
  8. public bool Validate(string account, string password)
  9. {
  10. Console.WriteLine("账号:{0}", account);
  11. Console.WriteLine("密码:{0}", password);
  12. //模拟登录
  13. if (account.Equals("张无忌") && password.Equals("123456"))
  14. {
  15. return true;
  16. }
  17. else
  18. {
  19. return false;
  20. }
  21. }
  22. //基本方法——抽象方法
  23. public abstract void CalculateInterest();
  24. //基本方法——具体方法
  25. public void Display()
  26. {
  27. Console.WriteLine("显示利息!");
  28. }
  29. //模板方法
  30. public void Handle(string account, string password)
  31. {
  32. if (!Validate(account,password))
  33. {
  34. Console.WriteLine("账户或密码错误!");
  35. return;
  36. }
  37. CalculateInterest();
  38. Display();
  39. }
  40. }
  41. }

(2) CurrentAccount:活期账户类,充当具体子类。

  1. //CurrentAccount.cs
  2. using System;
  3. namespace TemplateMethodSample
  4. {
  5. class CurrentAccount : Account
  6. {
  7. //覆盖父类的抽象基本方法
  8. public override void CalculateInterest()
  9. {
  10. Console.WriteLine("按活期利率计算利息!");
  11. }
  12. }
  13. }

(3) SavingAccount:定期账户类,充当具体子类。

  1. //SavingAccount.cs
  2. using System;
  3. namespace TemplateMethodSample
  4. {
  5. class SavingAccount : Account
  6. {
  7. //覆盖父类的抽象基本方法
  8. public override void CalculateInterest()
  9. {
  10. Console.WriteLine("按定期利率计算利息!");
  11. }
  12. }
  13. }

(4) 配置文件App.config,在配置文件中存储了具体子类的类名。

  1. <?xml version="1.0" encoding="utf-8" ?>
  2. <configuration>
  3. <appSettings>
  4. <add key="subClass" value="TemplateMethodSample.CurrentAccount"/>
  5. </appSettings>
  6. </configuration>

(5) Program:客户端测试类

  1. //Program.cs
  2. using System;
  3. using System.Configuration;
  4. using System.Reflection;
  5. namespace TemplateMethodSample
  6. {
  7. class Program
  8. {
  9. static void Main(string[] args)
  10. {
  11. Account account;
  12. //读取配置文件
  13. string subClassStr = ConfigurationManager.AppSettings["subClass"];
  14. //反射生成对象
  15. account = (Account)Assembly.Load("TemplateMethodSample").CreateInstance(subClassStr);
  16. account.Handle("张无忌", "123456");
  17. Console.Read();
  18. }
  19. }
  20. }
  1. 结果及分析

编译并运行程序,输出结果如下:

  1. 账号:张无忌
  2. 密码:123456
  3. 按活期利率计算利息!
  4. 显示利息!

如果需要更换具体子类,无须修改源代码,只需修改配置文件App.config,例如将活期账户(CurrentAccount)改为定期账户(Saving Account),只需将存储在配置文件中的具体子类CurrentAccount改为SavingAccount,如下代码所示:

  1. <?xml version="1.0" encoding="utf-8" ?>
  2. <configuration>
  3. <appSettings>
  4. <add key="subClass" value="TemplateMethodSample.SavingAccount"/>
  5. </appSettings>
  6. </configuration>

重新运行客户端程序,输出结果如下:

  1. 账号:张无忌
  2. 密码:123456
  3. 按定期利率计算利息!
  4. 显示利息!

如果需要增加新的具体子类(新的账户类型),原有代码均无须修改,完全符合开闭原则。