我发现中国人都喜欢统一。统一的思想已经深深的印在了中国人的基本思维模式里。
比如说设计一个接口,哎我能不能用一个接口让所有的客户都用这个,甚至这个接口也能承载不同的业务,这样一个接口就可以管所有的了。用户使用这个接口看似不需要学习,看似成本最低。
只有一个接口,一个接口统一一切,这个就是中国人骨子里的统一的思维。
很遗憾,一旦开始追求统一,那么这样设计就是错的。
我就不谈代码了,我举个最简单的例子,你去体检。
你到A医院,A医院给你一张纸,纸上title两个大字“体检”,接下来有三行:儿童体检,成年人体检,老年人体检。你需要用笔勾选一个,交给医生。
你到B医院,B医院给你三张纸,第一张纸上title四个大字:儿童体检;第二张纸上title五个大字:成年人体检;第三张纸上title五个大字:老年人体检。你需要选择一张纸,交给医生。
下面我们来分析这个问题。
首先从你方便快捷的角度。
你到了A医院,拿到了一张纸,看到了title两个大字“体检”,但这信息对你没用,你还得继续看下去,哦看到下面有3个不同的选项。
你到了B医院,拿到了三张纸,你直接看每张纸的title,哦有3个不同的选项。
注意到我前面加粗的字了吧,那么奥卡姆剃刀告诉我们,如无必要,勿增实体。A医院增加了毫无意义的一层,而你不得不去接受这额外的无用信息,这就导致了感官上没有B医院来的直接。
所以你在A医院的方便快捷程度不如在B医院的方便快捷程度。
这个例子可能过于极端,其实差别非常不明显。但如果你想象A医院是你每天写code要调用50次的一个库,B医院也是你每天写code要调用50次的一个库,你在写A的时候每次都比写B要慢个那么几秒钟,那么一天下来就是几分钟,一年下来就是几小时。
几小时听上去可能也没什么,但现实情况是,你可能不得不在写A这个调用的时候费劲的去选择多个参数的不同的组合,而B已经把组合整理好了给你了。
比如说,你去点菜,你去A餐馆,给你一本厚厚的菜谱,杂乱无章,你前后看了半小时,还是不知道该点啥。你去B餐馆,B餐馆给你好几本菜谱:儿童菜谱,成年人菜谱,老年人菜谱,肉类,蔬菜,海鲜,分门别类,每样都是一本小菜谱,而且每本小菜谱里都是价格从低到高,那是不是好选多了,你是不是还想立马应用下二分排序。
再怎么说,这对你来说,总归A比B也就是增加了有限的effort。但是对于医院或者餐馆而言,A比B增加了其实非常多的effort。
比方说A医院现在增加了一项入职体检,那么A医院得把原来所有的纸都作废了,重新全部打印多了一个选项的新的纸;或者A医院比较节省,那么它也得在所有已经有的纸上再用笔写上这个新的选项。而B医院只要重新打印新的纸就行了。
总之,A医院必须修改现有的模板,而B医院只需要添加新的东西,已有的东西不用改。那么A医院改模板的时候万一把已经有的前面三个选项不小心改错了呢?
这就是我们说的一个基本principle,Open-Close:open for extension, but closed for modification.
餐馆也是一样的,新出了一个菜品,A餐馆得修改整个菜谱,B餐馆只需修改一本小菜谱,改动越小,出错概率越低。
真实的码农世界要比上面的简单例子复杂的多。500行以上的文件,改起来effort很大,很容易出错。但如果能很好的分成5个100行的小文件呢,改起来就方便了。
《设计心理学2:与复杂共处》一上来就直接告诉你,复杂性,或者说实现一个东西的复杂程度,它是由你要实现的功能决定的,你要实现这么多功能,那么它就必须这么复杂。复杂性只能从你的设计的某一部分转移到你的设计的另一个部分,而不会减少。
但是我们可以设计我们的产品以使得复杂性以一种人类易于学习和理解的方式呈现出来。所以设计的目的不是要去消减复杂性,而是要让人能更容易的,消耗更少effort的,去让他们理解,学会和掌握这个复杂性。
呼应文章开头,一个统一的接口,它只是把复杂性藏在了它下面的各种参数里面了,但是复杂性还在那里,而且那里肯定有很多if else,这种呈现方式其实对于实现它的人来说是很不利的。
一个好的设计应该是提供尽可能多的选择,应该是在逻辑的起始之初就力求能把概念用实体进行区分,不创造所谓的统一的但其实并无太大意义的概念实体。
请使用Divide and Conquer的思想,统一的思想在码农的世界是不适用的。
实在想不通,想一想java的Collection package,里面各种Collection class,你每次用是不是还要去想该用哪个。但即便这样,它也没给你一个唯一的Collection class,然后你传参数告诉它你要用那个吧。method的数量可比class的数量多多了,传参怕是要累死的。。