前段时间知乎上有人发了这么个段子:
某日,老师在课堂上想考考学生们的智商,就问一个男孩: “树上有十只鸟,开枪打死一只,还剩几只?”
男孩反问:“是无声手枪,还是其他没有声音的枪么?”
“不是.”
“枪声有多大?”
“80~100分贝.”
“那就是说会震的耳朵疼?”
“是.”
“在这个城市里打鸟犯不犯法?”
‘不犯.”
“您确定那只鸟真的被打死啦?”
“确定.”老师已经不耐烦了,”拜托,你告诉我还剩几只就行了,OK?”
“OK.鸟里有没有聋子?”
“没有.”
“有没有鸟智力有问题,呆傻到听到枪响不知道飞的?”
“没有,智商都在200以上!”
“有没有关在笼子里的?”
“没有.”
“边上还有没有其他的树,树上还有没有其他鸟?”
“没有.” “方圆十里呢?” “就这么一棵树!”
“有没有残疾或饿的飞不动的鸟?”
“没有,都身体倍棒.”
“算不算怀孕肚子里的小鸟?”
“都是公的.”
“都不可能怀孕?”
“………,决不可能.”
“打鸟的人眼里有没有花?保证是十只?”
“没有花,就十只.” 老师脑门上的汗已经流下来了,
下课铃响起,但男孩仍继续问:“有没有傻的不怕死的?”
“都怕死.”
“有没有因为情侣被打中,自己留下来的?”
“笨蛋,之前不是说都是公的嘛!”
“**可不可以啊!”
“………….,性取向都很正常!”
“会不会一枪打死两只?”
“不会.”
“一枪打死三只呢?”
“不会.”
“四只呢?”
“更不会!”
“五只呢?”
“绝对不会!!!”
“那六只总有可能吧?”
“除非你他妈的是猪生的才有可能!一枪只能打死一只!”
“…好吧,那么所有的鸟都可以自由活动么?”
“完全可以.”
“它们受到惊吓起飞时会不会惊慌失措而互相撞上?”
“不会,每只鸟都装有卫星导航系统,而且可以自动飞行.”
“恩,如果您的回答没有骗人,”学生满怀信心的回答,“打死的鸟要是挂在树上没掉下来,那么就剩一只,如果掉下来,就一只不剩.”
老师推推眼镜,强忍着要昏倒的感觉,颤抖地说道:“你可以去当程序员了……”
有人就在下面问怎么写代码才能避免一连串的if else?
因为他用Python,我就回答:把每一个条件判断都写成一个布尔函数,把这些函数依次放进一个数组/列表。再写一个函数来遍历数组,对每一项,若为假则返回,若为真则继续。
对Java(8之前)来说,没有一等函数,就要把每个条件判断写成Function接口的实现类。
而用Java 8来写,就是:
Collection> conditions = new ArrayList<>();
conditions.add(context -> isGunSilent(context));
conditions.add(context -> isGunSoundBig(context));
conditions.add(context -> isShootingBirdLegal(context));
...
public boolean judge(Context context, Collection> conditions) {
for (Function cond : conditions) {
if (!cond.apply(context)) {
return false;
}
}
return true;
}
Context是个包装类,包含了gun, city, bird, tree等数据。
折腾之后,代码量相比一连串if else略有减少,似乎收益不大?噢,值得注意的是,这种方法具有高度的灵活性!
这些条件可以提前定义好,然后到处复用!你可以任意地组合它们,来构造一段业务逻辑,只需要挑选你要的条件,塞到一个list里面!简直棒!
这是用了哪种设计模式呢,比较像Strategy,我认为还像Template Method: 定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。
我们定义了作为骨架的judge():for循环,遇到false中止。然后在把步骤在子类中实现(虽然与judge()不属于同一个父类)。
虽然结构跟书上不一样,但是有相同的精神。
Chain of Responsibility需要前后链接,节点对其后的子链有控制力,所以不那么像。