当前位置:网站首页>梁老师小课堂|谈谈模板方法模式
梁老师小课堂|谈谈模板方法模式
2020-11-08 23:53:00 【公众号_松华说】
众多设计模式中,我觉得模板方法模式是很好理解,也很值得深入研究的技巧。定义如下,在一个包含多个步骤的业务框架中,大部分步骤是固定不变,并且适用于多种业务场景,可变的步骤则留给子类独立实现,从而分离了稳定和变化。
使用这种模式稍不留心,就会出现一些奇奇怪怪的问题。第一个是多个抽象方法会修改相同的变量,方法间出现强关联,第二个问题是定义了过多的抽象方法。后者正是今天想和你聊的话题,跟着我的步伐往下看吧。
一、为什么会出现这种问题?
我认为是这样的,产品经理从业务角度告诉我们,这个功能涉及到哪些步骤,每个步骤需要完成哪些事,然后我们就照搬概念将其转换成代码,考虑到有些步骤会涉及到多个实现,于是留了很多扩展方法。
不久后,新的业务需要复用这些流程,需要步骤1\2\3,但是不需要步骤4\5,甚至看不懂步骤4\5是做什么的,也不知道什么条件下会被调用,原有设计就显得不够简单了。
怎么理解这里说的简单呢?简单是站在人的角度来看的。假如,定义者和实现者来自两个不同的团队,实现者阅读文档后还需要定义者解释,才知道怎样实现抽象方法是正确的,那它就是复杂的。这个是我的真实感受,之前我在做中台通用能力建设,通过扩展点对外赋能时,思考最多的就是如何让第三方快速理解并上手。
总结一下,生搬硬套需求文档,让执行顺序完整地反映在代码结构中,会导致模板方法模式出现了过多的抽象方法。
二、出现了怎么办?
出现了过多的抽象方法怎么办呢?其实我们可以利用接口适配器模式来打补丁。
实际做法是这样的,创建一个抽象类Wrapper,实现所有的方法,方法实现不需要具体业务含义。当我们编写具体实现类时,继承Wrapper类,重写它自己关心的方法,这样就不用实现不了解的步骤了。
使用接口适配器来兼容可能还不够,考虑这样的情况,模板中的抽象方法明确需要有返回值,要怎么处理呢?
看来只好继续打补丁了。比如,定义一些默认值,业务流程中对这些值进行抛弃处理。或者,方法默认实现运行时抛出异常,表明不支持该操作,必须有第三方实现才行。这两个方案其实都不好。第一种有特殊逻辑,估计会被很多人鄙视。第二种方案相对优雅一些,缺点是调试过程才能发现异常。
总结一下,使用接口适配器模式,让子类只关心它需要的方法,这样就把旧代码、脏代码盘活了。
三、如何避免出现过多的抽象方法?
模板方法模式出现过多的抽象方法,侧面说明了流程步骤繁杂,不够简单。所以,这个问题的另外一种描述是,模板方法设计时如何避免暴露过多的细节。
我的建议是,对业务逻辑进行整理,把同类行为进行提取,或者把共享很多信息的方法合并,用一个通用的术语来概括这个环节,把细节隐藏起来,再用组合的方式加载进来,不要把代码直接平铺。
举例说明一下。在一个请求链路中,中间方法通过缓存客户端直接控制缓存的清除、缓存值的设置,其他链路则读取缓存值。这种编码风格,会把缓存Key、缓存组件暴露给第三方,导致后续修改困难。正常应该新建一个业务类,专门与该缓存Key打交道。
总结一下,避免出现过多的抽象方法的关键是如何避免暴露过多的细节。
本文分享自微信公众号 - 松华说(songhuasay)。
如有侵权,请联系 [email protected] 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。
版权声明
本文为[公众号_松华说]所创,转载请带上原文链接,感谢
https://my.oschina.net/liangsonghua/blog/4708396
边栏推荐
- Python的特性与搭建环境
- Octave basic syntax
- 国内三大云数据库测试对比
- 云计算之路-出海记-小目标:Hello World from .NET 5.0 on AWS
- Fiddler can't grab requests from browsers like Google_ Solution
- 200 programmers interview experience, all here
- Creating a text cloud or label cloud in Python
- getBytes之 LengthFieldBasedFrameDecoder服务端解析
- Deep copy
- 快来看看!AQS 和 CountDownLatch 有怎么样的关系?
猜你喜欢
随机推荐
Fiddler can't grab requests from browsers like Google_ Solution
EntityFramework Core上下文实例池原理分析
RabbitMQ快速入门详解
Introduction and application of swagger
200人的程序员面试经验,都在这里了
CSP-S 2020 游记
VIM 入门手册, (VS Code)
API生命周期的5个阶段
Case analysis of entitycore framework
c++11-17 模板核心知识(二)—— 类模板
C/C++学习日记:原码、反码和补码
为什么需要使用API管理平台
云计算之路-出海记-小目标:Hello World from .NET 5.0 on AWS
APP 莫名崩溃,开始以为是 Header 中 name 大小写的锅,最后发现原来是容器的错!
你有没有想过为什么交易和退款要拆开不同的表
Dynamic query processing method of stored procedure
寻找性能更优秀的不可变小字典
What courses will AI programming learn?
Using annotation + interceptor to implement asynchronous execution
Python features and building environment