在很多时候,我们在写代码的时候总是会遇到一些相同或者类似的处理流程和步骤,就拿一般的函数编写来说,在处理之前一般会进行参数有效性验证,然后可能会对参数进行预处理,最后在执行业务操作。

这种情况通常会出现在一类业务,比如订单处理系统中,就有订单创建,订单修改等操作,就会出现的这些类似的情况。 如果每个都这样写的话,会发现整个流程比较重复和冗余。比如:

class SomeProcessService
{
    ResponseBody SomeProcess (RequestBody request)
    {
        ValidateParameter();
        PreprocessingParameter();
        DoSomething();
    }
}

class AnotherProcessService
{
    ResponseBody SomeProcess (RequestBody request)
    {
        ValidateParameter();
        PreprocessingParameter();
        DoSomething();
    }
}

我们可以将以上的相同的处理步骤或者算法,抽象出来形成一个抽象类,在抽象类中指定处理步骤,然后分别编写子类实现各自具体的操作步骤。这其实就是模板方法设计模式。

这里以创建一个服务类为例,我们有订单创建和订单处理两个子服务,首先我们定义一个抽象类,该抽象类定义了参数和返回值泛型类,方法的处理骨架,如下,新建一个ServiceBase类:

abstract class ServiceBase<TRequest, TResponse> 
    where TRequest : class
    where TResponse : class
{
    /// <summary>
    /// 构造函数,接受请求参数,保存,后续处理所需要的参数信息保存在里面
    /// </summary>
    /// <param name="request"></param>
    public ServiceBase(TRequest request)
    {
        this._request = request;
    }


    /// <summary>
    /// 执行方法的模板或者骨架
    /// </summary>
    /// <returns></returns>
    public TResponse Execute()
    {
        //验证
      this.Validate();
        this.PreProcess();
        return this.ExecuteCore();
    }


    /// <summary>
    /// 验证,可以提供默认实现
    /// </summary>
    protected virtual void Validate()
    {
        if (this._request == null)
        {
            throw new ArgumentNullException("the request is null");
        }
    }

    /// <summary>
    /// 对参数进行预处理,比如添加一些默认信息等等
    /// </summary>
    protected virtual void PreProcess()
    { 
        
    }

    /// <summary>
    /// 执行实际操作
    /// </summary>
    /// <returns></returns>
    protected abstract TResponse ExecuteCore();

    /// <summary>
    /// 私有保存请求参数的字段
    /// </summary>
    protected TRequest _request;
}

然后在编写继承自ServiceBase的子类,这里为了演示,我们假设参数和返回值都是string类型:

internal sealed class OrderCreateService:ServiceBase<string,string>
{
    public OrderCreateService(string req)
        : base(req)
    { 
        
    }

    protected override void Validate()
    {
        base.Validate();
        Console.WriteLine("Valide the OrderCreateService Parameter: {0}", this._request);
    }

    protected override void PreProcess()
    {
        base.PreProcess();
        Console.WriteLine("PreProcess the OrderCreateService Parameter: {0}", this._request);
    }

    protected override string ExecuteCore()
    {
        Console.WriteLine("OrderCreateService is exceuting...");
        return "OrderCreateService execute Completed!";
    }
}

再创建一个OrderModifyService类

internal sealed class OrderModifyService:ServiceBase<string,string>
{
    public OrderModifyService(string req)
        : base(req)
    {

    }

    protected override void Validate()
    {
        base.Validate();
        Console.WriteLine("OrderModifyService: Valide the OrderModifyService Parameter: {0}", this._request);
    }

    protected override void PreProcess()
    {
        base.PreProcess();
        Console.WriteLine("OrderModifyService: PreProcess the OrderModifyService Parameter: {0}", this._request);
    }

    protected override string ExecuteCore()
    {
        Console.WriteLine("OrderModifyService: OrderModifyService is exceuting...");
        return "OrderModifyService:OrderModfiyServcie execute Completed!";
    }
        
}

使用的时候,我们使用子类实例化抽象类

ServiceBase<string, string> orderCreteService = new OrderCreateService("OrderCrete1");
string orderCreateServiceResult = orderCreteService.Execute();
Console.WriteLine(orderCreateServiceResult);

ServiceBase<string, string> orderModifyService = new OrderModifyService("OrderModify1");
string orderModifyServiceResult = orderModifyService.Execute();
Console.WriteLine(orderModifyServiceResult);

Console.ReadKey();

执行结果如下:

Template Model

在开发中,我们通常使用接口对外提供服务,所以我们可以让我们的抽象类实现一个接口,该接口里面仅包含执行部分(模板)的代码:

public interface IServiceBase<TResponse>
    where TResponse : class
{
    TResponse Execute();
}

这样,我们的抽象基础类变为:

abstract class ServiceBase<TRequest, TResponse> : IServiceBase<TResponse>
    where TRequest : class
    where TResponse : class
{
    /// <summary>
    /// 构造函数,接受请求参数,保存,后续处理所需要的参数信息保存在里面
    /// </summary>
    /// <param name="request"></param>
    public ServiceBase(TRequest request)
    {
        this._request = request;
    }


    /// <summary>
    /// 接口方法实现,执行方法的模板或者骨架
    /// </summary>
    /// <returns></returns>
    public TResponse Execute()
    {
        //验证
        this.Validate();
        this.PreProcess();
        return this.ExecuteCore();
    }


    /// <summary>
    /// 验证,可以提供默认实现
    /// </summary>
    protected virtual void Validate()
    {
        if (this._request == null)
        {
            throw new ArgumentNullException("the request is null");
        }
    }

    /// <summary>
    /// 对参数进行预处理,比如添加一些默认信息等等
    /// </summary>
    protected virtual void PreProcess()
    {

    }

    /// <summary>
    /// 执行实际操作
    /// </summary>
    /// <returns></returns>
    protected abstract TResponse ExecuteCore();

    /// <summary>
    /// 私有保存请求参数的字段
    /// </summary>
    protected TRequest _request;
}

使用的时候,上面可以注意到,我们将请求参数通过构造函数传进来了,并且标记为了protected关键字,这样子类中就可以访问该参数,使得具有更好的封装性。还有一点需要注意的是,如果模板方法中必须实现的方法,必须标记为abstract,可选的实现可以标记为virtual,并提供默认实现,比如参数验证valid的方法中,我们可以验证非空这种基本的错误情况。

改造之后,上面的类的方法调用方式如下:

IServiceBase<string> orderCreteService = new OrderCreateService("OrderCrete1");
string orderCreateServiceResult = orderCreteService.Execute();
Console.WriteLine(orderCreateServiceResult);

IServiceBase<string> orderModifyService = new OrderModifyService("OrderModify1");
string orderModifyServiceResult = orderModifyService.Execute();
Console.WriteLine(orderModifyServiceResult);

下面就是该方法的UML图:

Template Method model

以上就是模板方法设计模式的一个例子,它的基本思想就是 定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。希望对您了解模板方法这种设计模式有所帮助。