现如今当你翻看一些开源项目源码的时候,你会发现现在到处充斥着委托函数,如Func,Action,Predicate,确实现在的C#在函数式编程 的路上越来越成为主流,越来越显示威力,曾经的一些经典设计模式写法,在函数式下可以稍微优化一下了,这篇我们就来说说模板方法。

一:实际场景

1. 模板方法定义

相信这个模式在平时开发中会经常使用到,定义也很简单,在父类中定义算法骨架,骨架里面的某些细节点由相应的子类实现。

2. 业务场景

给用户推送彩信的时候,公司需要对接很多的彩信服务商,比如说博士通,助通,联合维拓,而每一家对提交彩信的格式有不同的要求, 比如说:博士通和助通会要求所有的内容按指定格式进行base64编码提交过去,联合维拓会要求你按指定格式打包成一个zip文件流过去, 这就是一个经典的模板模式,可以在父类中定义好构造彩信的算法骨架,具体细节可以由各自厂家子类实现,为了方便演示画图如下:

源码如下:

class MmsTemplate
{
    public virtual string GetHeader() { return string.Empty; }
    public virtual string GetBody() { return string.Empty; }
    public virtual string GetTail() { return string.Empty; }

    public virtual void ProcessRequest()
    {
        Console.WriteLine($"1. 彩信头:{GetHeader()}");
        Console.WriteLine($"2. 彩信体:{GetBody()}");
        Console.WriteLine($"3. 彩信尾:{GetTail()}");
    }
}

class ZhutongTemplate : MmsTemplate
{
    public override string GetHeader() { return "我是助通头!"; }

    public override string GetTail() { return "我是助通体!"; }

    public override string GetBody() { return "我是助通尾!"; }

    public override void ProcessRequest() { base.ProcessRequest(); }
}

class LianheweituoTemplate : MmsTemplate
{
    public override string GetHeader() { return "我是联合维拓头!"; }

    public override string GetTail() { return "我是联合维拓体!"; }

    public override string GetBody() { return "我是联合维拓尾!"; }

    public override void ProcessRequest() { base.ProcessRequest(); }
}

然后客户端可以根据指定通道配置调用相应的子类实现不同厂家的彩信体构建。

二:委托函数

1. 反思

在面向对象编程语言中,这种写法都堪称标准,我们先来捋一下流程,子类入口 -> 执行父类方法 -> 调用子类方法 如下图

从上图中可以发现一个问题,父类在执行算法骨架的时候,为了能够再次执行到该子类方法,在面向对象编程中必须要使用的技术就是多态,而为了构造多态,就必须在父类中定义一堆方法,然后由子类实现这一堆方法,这就是你看到的GetHeader(),GetTail(),GetBody()的由来,这时就显得有点老态龙钟。

2. 回调函数

仔细看一下这个xmind图,ZhutongTemplate类调用的MmsTemplate的方法,MmsTemplate在执行的时候再调用ZhutongTemplate的方法,前者叫调用,后者叫回调,如果还不明白,那前者叫送礼,后者叫回礼。。。对,既然在以前是用多态制造回调,那我是不是可以直接使用C#中的委托函数更简单粗暴呢?

3. 改造模板

直接看代码吧,千言难抵上代码。

class MmsTemplate
{
    protected Func<string> header;
    protected Func<string> body;
    protected Func<string> tail;

    public virtual void ProcessRequest()
    {
        Console.WriteLine($"1. 彩信头:{header()}");
        Console.WriteLine($"2. 彩信体:{header()}");
        Console.WriteLine($"3. 彩信尾:{tail()}");
    }
}

class ZhutongTemplate : MmsTemplate
{
    public override void ProcessRequest()
    {
        this.header = () => "我是助通头!";
        this.body = () => "我是助通体";
        this.tail = () => "我是助通尾!";

        base.ProcessRequest();
    }
}

class LianheweituoTemplate : MmsTemplate
{
    public override void ProcessRequest()
    {
        this.header = () => "我是联合维拓头!";
        this.body = () => "我是联合维拓体";
        this.tail = () => "我是联合维拓尾!";

        base.ProcessRequest();
    }
}

从上面代码中可以看到,原来需要多态实现的地方直接由委托变量接管,看起来是不是比之前的多态版简洁了很多。

好了,本篇就说到这里,更多的变通玩法期待您的发现~