设计模式之模板方法模式

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式之模板方法模式相关的知识,希望对你有一定的参考价值。

模板方法模式通俗点讲,就是通过在抽象类里,有一个总的方法来管理各个流程

而这些具体的流程可以自己实现也可以交给子类去实现。

在相同的方法里要实现不同的功能,不是使用分支的形式去处理,而是使用创建子类来重写实现。

这是因为,在一个方法里,当一个方法要实现的功能很多,可能超过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的值都是在运行时候决定的

以上是关于设计模式之模板方法模式的主要内容,如果未能解决你的问题,请参考以下文章

行为型设计模式之模板方法模式

设计模式之模板方法模式(Template Method)详解及代码示例

GOF23设计模式之模板方法模式(template method)

设计模式之模板方法模式

《Java设计模式》之模板方法模式

设计模式之模板方法模式