zoukankan      html  css  js  c++  java
  • 设计模式之模板方法模式

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

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

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

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

  • 相关阅读:
    13.Convert BST to Greater Tree(将树转为更大树)
    13.调用数组顺序使奇数位于偶数前面
    12.数值的整数次方
    11.二进制中1的个数
    12.Hamming Distance(汉明距离)
    11.Find All Numbers Disappeared in an Array(找出数组中缺失的数)
    10.Find All Anagrams in a String(在一个字符串中发现所有的目标串排列)
    垃圾收集器与内存分配策略---垃圾收集器
    线程之间的协作
    1287. Mars Canals(DP)
  • 原文地址:https://www.cnblogs.com/BigDong/p/8053037.html
Copyright © 2011-2022 走看看