模板方法的使用

一、场景:
最近在优化一个以前的系统,存在一个如下的场合:
我们目前有三个种类型的合集包(官方合集包、游戏合集包、渠道合集包),以前的代码在实现上都是都通过在一个函数当中添加【if...else...】条件来处理不同种类合集包的不同处理,这样的做的结果就是这个函数的结构越来越庞大,每次变动一个类型处理都可能影响其他类型的处理。所以呢想要优化整个实现过程。

二、思路:
1.想要减少 switch 和 if,首选的应该就是工厂方法,提供一个统一的入口
2.对于每一种合集包,其实大部分的处理都是一样的,只有几个步骤是需要特殊处理的, 这样又想到了建立一个基类和抽象方法,然后创建几个合集包处理的子类实现这些抽象方法,来达到自定不同处理的目的,这就是模板方法。

三、分析:
在编写代码之前需要先分析一下整个处理流程。如下图是一个合集包展示的数据,可以看到有顶部banner、灰色的数据、黑色的数据以及白色的数据数据。

例如 正常一个包的处理流程如下:

1.获取顶部的banner信息 这里所有的合集包类型处理的逻辑是一样的

2.灰色部分数据,官方合集和其他两种方式取得的方式不一样

3.黑色部分数据,游戏合集和其他两种方式取得方式不一样

4.白色部分三种类型都是不一样的

 

四、实现

1.既然是模板方法,首先就要有个模板,定义一个基类 CollectionParserBase.cs 默认实现的是官方合集的处理。

代码如下:

public interface ICollectionParserBase
{
    void GetGameCollection();
}

/// <summary>
/// 合集基础处理类
/// </summary>
public class CollectionParserBase: ICollectionParserBase
{
    private readonly ILogger<CollectionParserBase> _logger;

    /// <summary>
    /// 构造函数
    /// </summary>
    public CollectionParserBase(ILogger<CollectionParserBase> logger)
    {
        _logger = logger;

    }

    public void GetGameCollection()
    {
        GetBannerInfo();
        GetGreyInfo();
        GetBlackInfo();
        GetWhiteInfo();
    }

    public virtual string GetBannerInfo()
    {
        return "我是通用Banner数据";
    }

    public virtual string GetGreyInfo()
    {
        return "我是【官方合集】灰色数据";
    }

    public virtual string GetBlackInfo()
    {
        return "我是【官方合集】和【渠道合集】黑色数据";
    }

    public virtual string GetWhiteInfo()
    {
        return "我是【官方合集】白色数据";
    }
}

2.实现三种合集自己的处理类

①官方合集

/// <summary>
/// 官方合集处理
/// </summary>
public class OfficialCollectionParser : CollectionParserBase
{
    public OfficialCollectionParser(ILogger<CollectionParserBase> logger) : base(logger)
    {

    }
}

②渠道合集

/// <summary>
/// 渠道合集处理类
/// </summary>
public class ChannelCollectionParser : CollectionParserBase
{
    public ChannelCollectionParser(ILogger<CollectionParserBase> logger) : base(logger)
    {
    }

    public override string GetGreyInfo()
    {

        return "我是【渠道合集】灰色数据";
    }

    public override string GetWhiteInfo()
    {

        return "我是【渠道合集】白色数据";
    }
}

③游戏合集

    /// <summary>
    /// 游戏合集处理类
    /// </summary>
    public class GameCollectionParser : CollectionParserBase
    {
        public GameCollectionParser(ILogger<CollectionParserBase> logger) : base(logger)
        {
        }
     
        public override string GetBlackInfo()
        {

            return "我是【游戏合集】黑色数据";
        }

        public override string GetGreyInfo()
        {

            return "我是【游戏合集】灰色数据";
        }

        public override string GetWhiteInfo()
        {

            return "我是【游戏合集】白色数据";
        }
    }

 

3.创建一个简单的工厂,用来返回不同的Paser

public interface ICollecitonPaserFactory
{
    ICollectionParserBase GetCollectionParser(string collectionKindstr);
}

public class CollecitonPaserFactory : ICollecitonPaserFactory
{
    protected readonly IServiceProvider _serviceProvider;

    /// <summary>
    /// 构造
    /// </summary>
    /// <param name="serviceProvider"></param>
    public CollecitonPaserFactory(IServiceProvider serviceProvider)
    {
        _serviceProvider = serviceProvider;
    }

    /// <summary>
    /// 获取合集处理程序
    /// </summary>
    /// <param name="collectionKind"></param>
    /// <returns></returns>
    public ICollectionParserBase GetCollectionParser(CollectionKind collectionKind)
    {
        CollectionParserBase collectionParser = null;

        switch (collectionKind)
        {
            case CollectionKind.OfficialCollection:
                collectionParser = _serviceProvider.GetRequiredService<OfficialCollectionParser>();
                break;
            case CollectionKind.GameCollection:
                collectionParser = _serviceProvider.GetRequiredService<GameCollectionParser>();
                break;
            case CollectionKind.ChannelCollection:
                collectionParser = _serviceProvider.GetRequiredService<ChannelCollectionParser>();
                break;
            default:
                collectionParser = _serviceProvider.GetRequiredService<CollectionParserBase>();
                break;
        }

        return collectionParser;
    }
}

 

对了,因为使用了IOC容器,别忘了注册一下

public static class ServiceExtensions
{
    public static IServiceCollection AddServices(this IServiceCollection services)
    {
        //合集相关
        services.AddSingleton<CollectionParserBase>();
        services.AddSingleton<OfficialCollectionParser>();
        services.AddSingleton<GameCollectionParser>();
        services.AddSingleton<ChannelCollectionParser>();
       services.AddSingleton<ICollectionAppHelperService, CollectionAppHelperService>();
       services.AddSingleton<ICollecitonPaserFactory,CollecitonPaserFactory>();
       return services;
    }

 

五、使用

注入工厂服务,然后根据传入的collectionKind,获取不同的合集的Parser,然后调用GetGameCollection方法,获取数据。

[Route("api/collection")]
public class CollectionController : Controller
{

    private readonly ICollecitonPaserFactory _collecitonPaserFactory;


    public CollectionController(ICollecitonPaserFactory collecitonPaserFactory)
    {
        _collecitonPaserFactory = collecitonPaserFactory;
    }

    /// <summary>
    /// 加载卡片信息
    /// </summary>
    /// <returns></returns>
    [HttpGet]
    [Route("loadInfo")]
    public List<string> LoadInfo(CollectionKind collectionKind)
    {
        var parser = _collecitonPaserFactory.GetCollectionParser(collectionKind);

        var result = parser.GetGameCollection();

        return result;

    }

这里定义的枚举如下:

    public enum CollectionKind
    {
        /// <summary>
        /// 官方合集
        /// </summary>
        [Description("官方合集")]
        OfficialCollection = 0,
        /// <summary>
        /// 渠道合集
        /// </summary>
        [Description("渠道合集")]
        ChannelCollection = 1,
        /// <summary>
        /// 游戏合集
        /// </summary>
        [Description("游戏合集")]
        GameCollection = 2,
    }

启动运行一下

 

posted @ 2019-01-09 19:36  奋斗的大橙子  阅读(356)  评论(0)    收藏  举报