首先,我得承认自己在设计模式的修炼上还仅仅只是刚刚踩上登山的石阶,抬头望去,山腰还十分遥远,山顶更是远在实现之外。
工作满了一年那会,看到不少人在讨论和学习设计模式,于是乎,随大流的买了一本《Head First 设计模式》,花了一个月左右,把它看完了。这确实是一本不错的入门书。看完之后,跃跃欲试,挺想把设计模式用到工作中的,但是想起书上反复提到的不要滥用设计模式,为了模式而模式,所以在纠结中,把好些个类做成了单例模式(好吧,这几个单例做得没什么坏处,但是也没多少好处,仅仅是为实例提供了一个全局访问点,方便了编程,不用记得把实例传来传去罢了),之后,就渐渐淡去了对设计模式的兴趣,没有在上面花多少力气。
之后的这两年里,虽然不曾刻意的使用,但是简单的工厂方法,组装模式,单例模式,观察者模式等也不时出现在我的工作代码中,使用的时候没有想太多,自然的也就用了。的确,这些模式帮助我以更加清晰的逻辑去构建我的代码,但是,如果问我用了这些模式有什么好处,似乎也说不上来,用了也仅仅是因为其他似乎也没有什么更好的办法。
也曾经在一些demo等代码中,遇到过一些设计模式使用的绝佳案例,读到的时候真的觉得这个模式有种“舍我其谁”的精妙感,看似简简单单的一个模式,但是真的有中化腐朽为神奇,画龙点睛的感觉,深深觉得自己差得好远好远。
我们使用设计模式的目的很多,为了更好的可维护性,更好的可扩展性,更好的可移植性,但是归结到两个字,就是重用。使用设计模式是存在成本的,时间、代码量甚至是程序的性能。尤其是,当项目基本成型之后,设计模式使用的成本就更加明显,除了以上的成本意外,还有因为修改引入新的bug的风险。
这里插入点插曲:个人觉得,从性能来说,尤其是时间性能来说,原始的面向过程编程(OPP)始终是性能最高的。但是,一份好的面向过程的code,对于开发者的能力要求比较高(即较高的人力成本),开发周期也比较长(较高的时间成本),加之计算机的性能增长和成本的降低,使面向对象编程(OOP)更加符合目前商业开发的需求,所以OOP大行其道。这和java和C#这些语言慢慢侵蚀C/C++的市场份额是一样的,无非是设备提供了更高的性能来让语言“浪费”而已,不过,整个项目而言,项目整体成本的降低使这些“浪费”变得物有所值。
言归正转,既然设计模式是一种成本,那么,仅当设计模式达到它的目的——重用的时候,设计模式的使用才是利大于弊的,否则弊大于利。
那如何做到重用呢? “封装变化”这一条相当之重要。很多设计模式都深切的表达了这条原则:
策略模式,简言之,就是封装了行为,因为行为在变化。
状态模式,就是封装了状态,因为状态在变化。
命令模式,就是封装了命令,因为命令在变化。
观察者模式,封装了观察者和被观察者,因为需要感知变化的观察者在变化。
迭代器模式,封装了容器,因为容器在变化。
......
使用设计模式的时候,我们就是要找到系统中现在或者未来变化的点,把变化封装起来,这样,我们才可以做到“向修改关闭,向扩展开放”,才可以做到“针对接口编程,不针对实现编程”,才可以做到“松耦合设计”;只有封装了变化,我们才能让我们才能够让新的变化到来的时候,原有的代码可以继续工作,而不需要重写,这才是重用。
可以说,封装变化是一切的开始,但是,捕捉变化的能力,是需要经验去积累的,没有足够的项目经历,很难猜测系统未来会发生何种变化。如果瞎猜,封装了不会变化的因素,那么,当变化到来的时候,你会发现,你准备的接口都没能用上,这样使用设计模式所带来的成本就无法收回,我们就“吃亏”了。
所以,在条件成熟之前,不要急于使用设计模式,否则偷鸡不成蚀把米。一个用不好设计模式,确成天把设计模式挂在嘴边,用在项目中的程序员,远远比一个不知设计模式为何物的程序员可怕的多。
写给未来的自己,希望一两年后,再看这篇文章的时候,能够有更深的体悟,能够意识到自己的进步。