模板方法模式通俗点讲,就是通过在抽象类里,有一个总的方法来管理各个流程
而这些具体的流程可以自己实现也可以交给子类去实现。
在相同的方法里要实现不同的功能,不是使用分支的形式去处理,而是使用创建子类来重写实现。
这是因为,在一个方法里,当一个方法要实现的功能很多,可能超过30行,这样会使代码难以阅读,而且耦合性高
模板方法模式说白了就是抽象abstract和虚函数virtual的运用,在开始讲这个模式之前,
首先来讲一下抽象的一些小知识,我们知道使用抽象可以使用abstract或是接口Interface,这两者有什么区别呢?
abstract:是告诉我们这个类大概是什么,抽象类不能自己实例化,他必须通过子类继承来实例。子类必须实现父类的抽象方法
在调用父类的抽象发法时,会直接调用子类的重写方法,1.抽象类可以定义普通方法的实时,也可定义抽象方法
2.抽象类可以定义非静态变量和静态变量,3.抽象类可以定义构造器,该构造器不为构建对象,只为子类提供构造方法
Interface:接口是告诉我们这个抽象类是干什么的,接口也不可以实例化,1接口只能定义静态变量
2.接口只能实现抽象方法。3.接口不能定义构造函数。
而我们的模板模式里面有普通方法,也有抽象方法,所以使用abstract比较合适
然后我们再来讲下abstract和virtual函数的区别
abstract:不包含实现函数体,继承的子类需要重写来实现他
virtual:又称钩子方法,它必须包含实现函数体,但是可以被子类重写,这样做的目的是为了
如果父类有一个方法,有两个子类都使用它,但第三个子类使用这个方法的时候有不同的地方,这时候我们就可以使用Virtual函数
下面我来举一个模板方法模式的例子,首先我们有一个抽象基类,用来模拟银行客户端,它里面有检查用户
查询账户密码,输出余额三个方法,我们直接上代码
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Threading.Tasks;
6
7 namespace 模板方法模式
8 {
9 /// <summary>
10 /// 银行客户端
11 /// </summary>
12 public abstract class Client
13 {
14 /// <summary>
15 /// 查询用户
16 /// </summary>
17 /// <param name="id">用户id</param>
18 /// <param name="name">姓名</param>
19 /// <param name="password">密码</param>
20 public void Query(int id,string name,string password)
21 {
22 if (this.CheckUser(id, password))
23 {
24 double balance = this.QueryBalance(id);
25 double interest = this.CalculateInterest(balance);
26 this.Show(name, balance, interest);
27 }
28 else
29 {
30 Console.WriteLine("账户密码错误");
31 }
32 }
33
34 /// <summary>
35 /// 检查用户
36 /// </summary>
37 /// <param name="id"></param>
38 /// <param name="password"></param>
39 /// <returns></returns>
40 private bool CheckUser(int id, string password)
41 {
42 return DateTime.Now < DateTime.Now.AddDays(1);
43 }
44
45 /// <summary>
46 /// 查询账户余额
47 /// </summary>
48 /// <param name="id"></param>
49 /// <returns></returns>
50 private double QueryBalance(int id)
51 {
52 return new Random().Next(10000, 1000000);
53 }
54
55 /// <summary>
56 /// 活期 定期 利率不同
57 /// </summary>
58 /// <param name="balance"></param>
59 /// <returns></returns>
60 public abstract double CalculateInterest(double balance);
61
62 /// <summary>
63 /// 显示余额
64 /// </summary>
65 /// <param name="name"></param>
66 /// <param name="balance"></param>
67 /// <param name="interest"></param>
68 public virtual void Show(string name, double balance, double interest)
69 {
70 Console.WriteLine("尊敬的{0}客户,您的账户余额为:{1},利息为{2}",name,balance,interest);
71 }
72 }
73 }
上面的代码可以看到,有具体的流程函数,这个函数里每个流程的功能都单独分开(这样不仅方便了代码的阅读,也使得模板模式可以进行)
我们有那个地方不同,例如利率计算的函数,定期和活期会不一样,这时候我们就把他变成抽象方法,然后创建子类来继承
而像如果有些方法会被多个调用,但少数调用时候会进行修改,就像下面这个函数一样,写成虚方法
这样子类就可以选择,如果不重写,就继续调用父类的方法,如果重写,就调用子类的方法
最后说一类实例的知识,普通类被实例的时候是由编译器决定的,例如 Class a=new Child();
Child继承于Class,两个类里都有相同的方法,然后输出这个方法,会输出父类里的,因为在编译的时候决定的就是Class的值
而abstract和virtual的值都是在运行时候决定的