三明治代码是代码复用的一种方案,或者一种思路
问题的产生
假如,现有一个需求,“去超市买一瓶矿泉水”,代码可能像这样:
- 走近超市
- 在入口处,检测体温(新冠啊,新冠!)
- 进入购物区
- 去找到一瓶矿泉水,并放到购物车里
- 去收银台接算
- 走出超市
过了几天,来了新需求,“去超市买一袋薯片”
那么把上面的代码,复制、粘贴,再把第 4 步改一下,就可以直接用了
那么,这时候,就产生了重复代码
小试牛刀
这个很容易解决:
封装个函数嘛,把要买的东西作为参数,传进去
function 去超市买东西(要买的东西) {
走近超市();
检测体温();
进入购物区();
加入购物车(要买的东西);
去收银台接算();
走出超市();
}
这很棒,用简单的方法,解决简单的问题
现实是非常复杂的
但现实问题往往没那么简单
我记得小时候,有的超市里是有小餐厅的,凉皮、卤菜……
点了想吃的东西,当场就需要付钱(不需要到出口处的收银台)
做好了立刻可以吃(不必在超市外吃)
那么,可能就会有这样的需求:
去超市吃个凉皮
显然,刚刚写的函数不好用了
但是,做些改动,就又行了:
function 去超市买东西(要买的东西, 要现场吃的东西) {
走近超市();
检测体温();
进入购物区();
if(要买的东西)
加入购物车(要买的东西);
if(要现场吃的东西) {
去小餐厅();
点餐(要现场吃的东西);
接算();
等餐();
吃();
}
去收银台接算();
走出超市();
}
是的,又行了,但不太好
因为,可能还有其他种类的服务,不适用这个函数
比如:
- 有可能要买衣服,而买衣服需要试穿一下
- 不同品牌的商品,不需要比对一下吗?不同类型的商品,其比较的“算法”一样吗?
- 超市里可能有小朋友的游玩区,家长在买东西的时候,可以把小朋友寄存在那里(当然,你可能没小孩,但有可能你自己想玩啊)
- ……
可以根据不同的需求,不断扩充上面的函数
但最后,它可能变成一个很大的函数,既丑陋,又不好维护
英雄登场
可以把在超市进行的操作,封装到一个函数里
然后把这个函数,作为参数,传给“去超市”函数
function 去超市(要做的事) {
走近超市();
检测体温();
进入购物区();
要做的事();
去收银台接算();
走出超市();
}
function 买条裤子() {
找一条喜欢的裤子();
试穿各种型号();
把合适的型号放入购物车();
在_服装区收银台_接算();
剪裤脚();
}
去超市(买条裤子);
不错吧~
总结
为什么叫“三明治代码”?
因为三明治,往往是上下两片面包,中间可能是煎蛋、可能是煎牛排、可能是蔬菜……
甚至是两片面包夹个三明治
上下不变(永远是面包),夹心,则需要发挥想象力,谁说没有臭豆腐夹心的三明治?
来看看上面的 去超市
函数:
function 去超市(要做的事) {
走近超市();
检测体温();
进入购物区();
// 上面三行,相当于三明治的“上层的面包”
要做的事(); // 夹心,千变万化,你甚至可以写一个“啥也不买,就看看”的函数
// 这下面,就相当于三明治的“下层面包”了
去收银台接算();
走出超市();
}
英雄返场
上面说的夹个三明治可不是开玩笑
比如,需求是这样的:
周末的时候,你在家,要去超市买一袋薯片
- 出门,下楼,走出小区
- 走向超市
- 去超市(买一袋薯片)
- 走回家
- 在小区门口测体温
- 进小区,上楼,进门
这时候,“去超市()”,就成了夹心
或者,你在家,不是去超市,而是去剪头发、菜市场……换换夹心就行了
或者,你在公司,下午,饥肠辘辘,需要去楼下的小超市买个…… 那就需要换面包了
或者,你在公司,要回家拿个东西
或者,你在家,要去公司拿个东西
……
没有绝对的面包或夹心
你可以用全麦面包夹煎蛋
也可以用荞麦面包夹生菜
也可以用两片全麦面包夹一片荞麦面包
也可以用两片煎牛排夹一片荞麦面包(肉夹馍?)
或者用两片荞麦面包夹上面的任意一种三明治