放过设计模式吧

太久不写博客,都不知道咋开头了。

主要是现在这设计模式的文章太多,而且各种烂各种曲解,看的人心烦,烦到忍不住想自己写一个系列把它们说清楚——但是呢,转念一想,我写的再怎么清楚能有GoF清楚呢,怎么能有GoF的影响力大呢,GoF明明白白地摆着,还有这么多人乱搞,我又能做什么呢?所以想了半天,我觉得就写一篇文章来吐槽好了。 - -!

说设计模式这个东西呢,不少网友跟我说起其实叫设计模式是很不对的,我也深有同感。pattern这个词有纹理、花纹的意思,外国人买布买窗帘的时候可能会挑挑pattern,这东西说成是模式就有点过了,所以我觉得这个东西其实翻译成《面向对象设计23招》比较好,这样也跟我朝的《网页特效50例》等畅销书比较对仗。

虽然一些同学对"设计模式"这个好听的词被抢感到不满,认为提到的时候应该加些修饰词,不过为了简单起见,咱们这里约定凡提到"设计模式"皆指GoF23模式。

设计模式针对的是面向对象的设计问题 

设计模式的另外一个巨大的问题就是它把面向对象和软件这两个重要的关键词放进副标题里面了,兼之作者非常骚包地在里面扯了一通模式界、建筑学这等事情,搞得好像这书超脱了语言和场景限制,"是一种编程思想"(加引号的原因是我觉得大师们欺骗新手最常见的手段就是故弄玄虚地说"语言都是浮云,编程思想最重要。"),只要写程序就必须模式一下什么的。当然GoF肯定不是故意骗大家了,其实也只能骗到那些只看正标题连副标题也不看的孩子,看了内容的话就更不会搞错了。

但是令我惊讶的是连副标题都不看的人确实不在少数,非要用跟面向对象毫无关系的方法实现设计模式的人真的很多啊......

说了半天其实我这里想说的是设计模式是面向对象编程中特有的一些技巧,是应用五大基本原则之后(单一职责、开放封闭、里氏代换、接口隔离、依赖倒置)产生的一些设计疑难问题的解决手段。在一些非纯的面向对象语言里面可能根本就不需要设计模式。

一个非常明显的例子就是,抽象工厂、工厂方法、原型三个模式要解决的是DIP应用以后的创建对象难题。

很多文章根本就不管什么DIP,举了一堆所谓"生活中的例子",神马造零件做汉堡的copy作业之类的,尼玛啊,这跟那些生活有毛关系啊,程序员的生活难道不就是写程序么?写程序难道不就必然要用到DIP么?用到DIP只依赖接口这东西不能new才需要这几个模式的啊,人家模式名字里面带工厂俩字没听说实现的业务就一定要跟生产有关系啊。

基于这种不知所谓的逻辑,这几个模式当然也可以用在JS、C什么的里面啦,因为JS也难免有描述鞋厂麦当劳的时候嘛。于是这些模式就华丽丽地成为了一种思想,抽象工厂变成了"描述一个一种对象可以产生另外一种对象这样的业务逻辑",原型变成了"描述一个对象可以copy自身这样的业务逻辑",更加华丽地是,这些业务逻辑模式还能被扭来扭曲实现成完全符合GoF上UML图的类结构啊.....

说到正经事,既然是因为遵循DIP才引入的几个模式,在JS这个没有接口的面向对象语言中,自然不存在使用的需求了。(但有趣地是,JS里面把原型作为几乎是唯一地创建对象手段,与本文主题无关,就不多说了。)而C++有模板这样强大的特性,很大程度上也不需要简单工厂和工厂方法(抽象工厂还是需要的)。同样的道理,拥有delegate和Event的C#里面也没有使用观察者模式的必要。

语义比UML重要1000倍

设计模式里面最不容易误解的就是UML了,凡讲设计模式的文章,就算扯得再不靠谱,一般UML也是对的...... 好吧UML也是对的这件事实在太容易,甚至比如策略模式和状态模式和桥接模式的UML都是基本一样的。

嗯,于是囧的事情出现了,比如http://en.wikipedia.org/wiki/Strategy_pattern 在煞有介事地对比策略和桥接到底有何不同。尼玛啊!!!!我怎么没想明白一个叫"实现",一个叫"算法",这俩东西肿么就能有交叉呢?

只看UML是不少设计模式文章的通病,嗯,通常情况下这时候"生活中的例子"又会登场了,语义则会被华丽丽地无视。最为悲惨的两个模式就是策略模式和桥接模式了,看来"算法"、"实现"、"抽象"这些词实在不太好理解。为了够"生活",譬如买油和买盐这等完全不相干的功能就被戴上了算法的帽子,GoF说的好"本模式使得算法可以独立于使用它的Client而变化",Client表示很无奈啊,就换了个算法而已,连结果都变了是怎么回事啊,刚才算的还是a+b,尼玛你一换算法结果变成a*b了?(嗯, 我在吐槽http://en.wikipedia.org/wiki/Strategy_pattern) 卧槽你想说a+b和a*b都是calculate这件事么?你怎么不干脆把所有方法都叫dosomething啊,那样全世界所有的事情都可以叫不同策略了啊!

桥接模式更悲剧了,"抽象"和"实现"这俩词怎么听着这么像接口和具体类啊,难道说......桥接模式其实就是LSP?再一看UML真简单啊,这不就是组合么?于是乱搞一个"生活中的例子"把UML对上就成了!我承认英文里面这俩词跟实现接口、抽象类有点像,翻译成中文更没区别了,但是GoF里面不是tmd还有例子呢么?不是还有解释呢么?GoF那Window的例子是多么的明显,抽象是业务相关的,实现是系统底层相关的。 

一些其它的模式和误解

Flyweight经常被以C#的字符串为例而搞成"神秘地节约内存方案",或者以内存池为例搞成只有外部状态的假对象。辨识正确的Flyweight模式实现的关键要素是内部状态和外部状态是否俱全。

Composite模式经常被误解为树形结构,辨识Composite模式的关键在于语义,几个X的组合是否仍然是X,而不是被X包含。举例子来说,几个几何图形的组合仍然是几何图形,而几个HTML节点的组合就不是一个HTML节点。

Decorator模式经常被搞成拼字符串用的(尼玛,这活还是交给StringBuilder之类的东西吧......),辨识Decorator的关键一是被装饰的是类而不是方法,二是语义上是否可以被再次装饰。 

结语 

设计这件事情很难用语言表达,因此要讲清楚设计是一件非常困难的事情,在博客园出现的设计模式文章我经常跑去给负面评论......但屡屡被教育"不要为了模式而模式"、"你对设计模式的理解,还仅限于GoF"、"只要遵循基本设计原则就可以"。(大约我朝受"无招胜有招"文化熏陶太久,导致大家还没等学会招呢,先奔无招去了......)设计模式的本意之一是提供一套通用的设计词汇,但是显然时至今日(至少在我朝),它自身都被各种歪曲误解。希望大家能够一起努力,一是以身作则,写文章的时候更严谨,二是擦亮眼睛,看文章的时候多查资料,消灭设计模式的各种歪解。

附上一张我的设计模式书的照片,以证明我确实读过GoF(挖咔咔咔咔)

 

看了朋友的一些评价觉得有必要提一下,

写此文的意思绝对不是要初学者不写设计模式的文章

我想表达的意思是(不限于设计模式)读书写文章的时候,应该更加严谨,不理解的地方,不能含糊代过甚至凭想当然,这样不论对人对己,都是更容易进步。


posted @ 2012-03-10 22:15 winter-cn 阅读(...) 评论(...) 编辑 收藏