模板方法的使用
一、场景:
最近在优化一个以前的系统,存在一个如下的场合:
我们目前有三个种类型的合集包(官方合集包、游戏合集包、渠道合集包),以前的代码在实现上都是都通过在一个函数当中添加【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, }
启动运行一下


浙公网安备 33010602011771号