聊一聊代码中的抽象

抽象是编写代码的基础,有效的认识代码中的抽象,对我们在项目实施中选择设计模式和架构都会有很大的帮助。
据我所知的抽象分为3种:

  1. 过程抽象
  2. 数据抽象
  3. 控制抽象

过程抽象

过程抽象是最常用的一种抽象,它是消除系统中重复代码头号方法。
例如,在一个App的页面上,当页面打开时,会加载数据;在App重新唤起时,会重新加载数据;当用户点击某个按钮时,会重新加载数据;
面对这种情况,我们通常会把这段代码抽象出来,将其放在一个函数中。

onLoad() {
  this.loadData();
}
onShow(){
  this.loadData();
}
onBuy(){
  ...
  this.loadData();
}

这样做的好处是当数据加载逻辑有变化时,修改的地方会被限制在loadData函数中,保证了逻辑的一致性。

控制抽象

控制抽象的抽象层次比过程抽象要高,先举一个例子。
在某个场景中,图片和文字都要按照一个优先级逻辑来处理。

const img = (isConfigured(record) && img1) || (isHot(reord) && hotImg) || (isCurrent(record) && currentImg)
const text = (isConfigured(record) && '已配置') || (isHot(reord) && '热销商品') || (isCurrent(record) && '当前商品')

在上面的代码中存在重复的控制逻辑,因此对代码进行重构,得到下面的代码。

const buildPrecedence(record)=>(configHandler, hotHandler, currentHandler)=>(isConfigured(record) && configHandler()) || (isHot(reord) && hotHandler) || (isCurrent(record) && currentHandler())
const precedence = buildPrecedence(record)
const img = precedence(()=>img1, ()=>hotImg, ()=>currentImg)
const text = precedence(()=>'已配置', ()=>'热销商品', ()=>'当前商品')

有趣的是,之前的两行代码变成了现在的四行代码,这也反应出了使用控制抽象的成本。但现在,如果要改变优先级处理逻辑,就只需要修改buildPrecedence。
个人认为,控制抽象更加接近于艺术,是艺术就会有美与丑。做得好的控制抽象,整个代码就利于他人的理解和维护;做得不好的控制抽象,代码可能过了一段时间连自己都要半天才能看懂。
因此,肯定会有大咖不同意上面的重构方式,这也很正常,因为控制抽象本身只是抽象方式的一种归类,而不是具体的实现方法。控制抽象是要去学习和创新的,这是为什么会有23中常用设计模式。

抽象带来的问题

因此,我们在实际的项目代码上可能会遇到2种典型的情况,一种是没有使用任何抽象,代码基本上就是从业务需求直接翻译过来。这种代码的好处是很容易理解,但因为同一条业务逻辑在业务流程中可能多次出现,因此按照这种思路写出来的代码也是多次重复的,因此不好维护,即一旦那条业务逻辑发生改变,就要对代码中对应的多个地方进行修改,而是否能够改完所有的地方全凭当事人的记忆,还有全文搜索的运气。

一种是使用了抽象设计,但这个抽象不够合理。注意,就算使用合理的抽象,当问题发生时,也会通过一层一层的引用去定位问题,这本身就比较麻烦。但如果这个抽象不够合理,这种麻烦的程度会大幅度加深,从而增加代码的维护难度。

我也作为万千程序员中的一员,几乎每天都在经受着抽象带来的考验。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

涵树_fx

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值