一、编程中抽象思维方法的重要性
世界非常复杂善变。程序员必须要应对这复杂善变的世界。如何应对?用抽象的方法。人类最重要的思维能力就是抽象的能力,计算机程序无论多智能,到目前为止,还是没有任何抽象能力。
设计系统、编写代码、代码演化的过程,必须是一个抽象的过程。
不能理解这一句话的程序员,不能称为一个优秀的程序员。
解释一下,何为程序员的抽象。程序员的抽象方法,一般指的就是封装。封装什么?封装变化,封装复杂性。能以不变应万变,是抽象的最高境界。
二、从一个简单的例子谈起
怎么,你还不明白?那我举个例子。
你需要编写一个计算三角形面积的代码。
过了几天,你又需要编写一个计算五边形面积的代码。
这时,如果你还不意识到,你需要将两部分的代码合并起来,封装成一个计算n边形面积的宏、或函数、或对象、或对象群、或模块、或应用程序,那么你就不是一个成熟的程序员。
因为,如果你不这样做,随着时间推移,将会发生如下问题:
一):将来,你,或者你的同事,还需要辛辛苦苦编写计算四边形面积、七边形面积的代码;
二):然后,系统中到处都是这几份代码的拷贝,代码体积膨胀;
三):你发现你用的公式有点问题,你想修改这个公式时,却发现不得不在系统内到处搜索,找到每一处使用这个代码的地方,并且一一阅读、修改、调试那些代码。这份工作不仅单调、令人厌烦,而且非常冒险,因为你不能确保你修改了那些代码后,那些文件是否能像你预期那样运行,也不知道你是否找到了系统中所有使用这些代码的地方。
四):最后,你发现这个系统已经不可维护:类似的代码到处都是,而且往往都有一些或大或小的差异。你祈祷你所写的这份代码是绝对正确、没有问题的,因为一旦出了问题,系统是不能修改的了。可惜得失,上帝也写不出这样的代码。
回头看看。如果你时一个成熟的程序员,在遇到变化的时候,就用函数,或者对象,将你这些代码封装起来了。那么上面所说的恶梦就不会出现,项目也不至于在最后变得无法收拾。
三、如何抽象?
呃,我有抽象的思想,但我不知道n边形的面积计算公式,不知道怎么写这个函数,怎么办?
别担心,程序员有自己的武器库。设计模式说到底,就是为了解决这种问题而存在的。
你写不出来的话,就留给以后需要的时候再写,或者留给你的同事以后写。重要的是,你要封装有这样的接口。而且要有让别人不必修改你的代码,就能往你接口里增加内容的能力。
不修改代码,就能往你接口里增添内容?如果你不熟悉设计模式,你可能觉得玄乎。请去重读几篇关于设计模式方面的文章吧。几乎所有设计模式,都是为了让代码有这样一种能力:增加功能时,只需增加模块,而不必修改原来的模块。
三、用设计模式来抽象:回到刚才的例子
扯远了,我们回头看n边形的计算公式怎么封装好吧。老实说,我也不知道这个公式该怎么写。我数学很糟糕,我只记得三角形、四边形的面积公式。但是不知道公式该怎么写,就更加要封装,不然将来会死的更惨。
我们有如下选择:
一)封装一个计算n边形面积的函数,但如果用户输入的不是三角形或者四边形,那么抛出一个异常,告诉使用者在这里添加一份他所需要的代码。
怎么,你觉的这样非常不友好?呃,我也同意,可是这是最自然的思路了。初级程序员写出这样的代码是可以奖赏的,说明他有些抽象的思想了,虽然还没有掌握抽象的方法。
二)封装一个计算面积的对象,该对象目前只提供计算三角形或四边形面积的成员函数。如果使用者发现这个对象没有他所需要的方法,请他修改这个对象,为它增加这个函数。
这种封装方法也不错,可惜没达到上面的目标。因为使用者为了给你增加方法,必须修改你的代码。
三)使用简单工厂模式。每一种多边形的计算方法,都封装成一个对象。使用者要计算面积时,首先根据该多边形的边数,调用工厂方法,得到对应的多边形计算对象,然后再进行计算。
这种方法的好处是:使用者发现增加一种多边形计算方法时,只要编写这样一个对象,然后修改工厂方法,把这个对象返回就行了。
这种封装不够彻底,因为还是要修改原来的代码。但是,已经足够有效了。因为工厂方法内,只是一组简单的case语句,修改它是不会出什么问的。
四)使用动态工厂模式。前面不是说不够彻底,工厂类还是要修改么?那么我将工厂类也封装一下。工厂类里,维护一组计算面积的对象列表。原来的工厂方法中的case语句,改为查询列表,返回相应的对象。对外提供一个register方法,让别人可以往这个工厂里增加新的计算面积的对象。
这是的代码就比较完美了。要增加新的计算面积的方法,完全不需要修改原来的代码,只要创建一个这样的对象,并把对象注册到工厂类里就行了。
比较不好的是,这时的代码并不是很适合于阅读。因为光看工厂类的代码,你不能知道这个工厂类究竟能提供哪些对象——事实上,这个工厂类变成了一个运行框架,没有任何具体的内容——它的能力和行为,是在运行的时候才能确定的。
按这种考虑,还是前面用简单工厂的模式比较好一些。
五)使用策略模式的方法。
嗯,不行。还有非常多的模式可以应对这种情况,我不能一一列举。我只是想举个例子,说明如何用设计模式来应对你所不了解的变化。
五、结语
实际上,上面这个计算多边形面积这个例子,可以套用到很多地方上。
比方说一个网络服务器,它要处理很多种类型的数据包。随着项目的发展,它所要处理的数据包的类型也会越来越多。你不可能知道下一个需要你处理的数据包类型是什么。此时,你可以套用前面的解决思路,或者,使用其它可以使用的设计模式
重要的是封装的思想,然后,要学会一些常用的封装方法。有了这两个能力,程序员才算成熟。
<a target=blank href=http://wpa.qq.com/msgrd?V=1&Uin=15193512&Exe=QQ&Site=im.qq.com&Menu=No>
<img border="0" SRC=http://wpa.qq.com/pa?p=1:15193512:1 alt="给我发消息"></a>