能写出琳琅满目的代码就能显示出你是真正的高手?错,真正的高手是拥有最重要的编程思想技术的,即使他现在所会的技术全部过时,他依旧可以迅速掌握新的技术,写出高质量的程序。
如今的框架和流行语言封装了大量实用的数据结构,甚至还有一些经典的算法,带给我们很大的便利,使用.NET简单拖拽出一个网站,虽然后台操作数据库绑定,处理数据,更新数据会有些重复无聊,后来接触了Linq,和thinkPHP(php的MVC)可以大大减少这些没太有技术含量的代码,写多了依旧觉得没太有意思,远没有自己写个小程序或者小游戏来的痛快。
记得我们数据结构老师曾经说:“算法是一种艺术。”然后,我们几乎全班报以不屑的表情,而我当时也曾是其光荣的一员。因此数据结构学的很烂,也很后悔。
算法书上提到扫雷,扫雷这个经典游戏,其中有个核心算法就是计算每个格子周围有多少个地雷。
我想玩过两年编程的人会迅速想到这样一个算法:用二维数组存储每个格子的信息,(当然地雷已经随即分配好了),然后遍历这个数组,遍历到一个就统计其周边八个方向的地雷数,将结果保存到当前遍历的数组项中。当然可以把统计的过程写成函数调用下。这个是最容易想到的算法。
后来我觉得这个还是有点浪费了,因为很多周围没有地雷的格子也都要扫描八个方向是否有雷,我开始转念去想,我要统计的是每个格子周围的地雷数,那么决定他地雷数的是什么呢,当然是地雷了,所以开始想到第二个算法,依旧遍历那个二维数组,只是仅当遍历到地雷时,将地雷周边八个方向的格子里的数值+1,这样大大缩小了统计的次数。这个应该属于逆向思维吧。
同理想做个象棋程序时会遇到“将军”的算法,判断自己的将军或者元帅是否处在下一步被吃掉的情况下(象棋术语叫将军)。当然很简单的算法就是遍历对方当前存在并且有攻击力的棋子,下一步是否有可能杀掉他的将。但我们也可以去反过来去想,既然是判断将是否处于被杀状态,那直接从他入手,判断其直线范围内是否有对方,“卒”“车”或“炮”,再判断自己周围的日字格内有没有对方“马”的存在等等去逆向想问题。
编程的感受
编程最重要的是一种思想,编程的真正快乐是设计一个算法赋予程序,每一个程序都是有生命力的,而算法是他们的魂魄,创造一个有生命力的程序当然是件快乐的事情,如果感到不快乐或者编程枯燥是因为在练习一些所谓的技术,所谓的方法和模式,而非为了编程而编程。
编程离不开技术,如同练武离不开招式一般。
境界高的武者常常说,功夫的最高境界是心中无招。而这种无招并非什么都不会,而是集了百家之长,融了千招万招之后,思想,招式,身体高度统一,随心所欲地见招拆招。也并非学遍所有招式便达到这种境界,要真正懂得思考招式之间内在的联系,慢慢融入成自己的思想,才有可能达到。
一些老程序员常常教育我们,编程最忌讳多而不精。
会的多并不代表是高手,会的少也不代表是菜鸟,编程重在思想,这种思想决定了你在这门技术里走的深度。
思想是什么,是解决问题的思路,是规划能力,分析能力,是迅速将解决问题的思路条理化。可以是算法,模式或者框架。
这些思想需要几年十几年的经验沉淀。
现在流行面向对象思想,简单地说一下从.NET以来对这个思想肤浅的认识,从之前C的大量函数库到现在的大量的类库(或java里的包)似乎有了类,就面向对象了,这个说法有些牵强,无论学习Java还是C++,最重要的是要用C++,Java去想问题,用面向对象去思考问题,将对象作为处理问题的基元。
上次去面试,面试官让我讲述面向对象的继承,多态,和封装的特性。
我给他讲了个我写过的简单坦克大战程序分析这三个特性。
继承:这个概念十分好理解,子类继承了父类的所有共有成员,比如一个坦克的基类,实现基本坦克特性和方法,如大小,生命值,移动,判断碰撞等,以后要设计一个独特的坦克,如幻影坦克(红警了),只需要继承下父类,再加一个幻影的方法就可以解决了。继承的优点也是显而易见的,对于绝大部分坦克共有的特性和方法写到基类,以后要设计新类型的坦克只要继承一下,省去了大部分代码。所以继承是最简单,也是最实用的。
多态:可以狭隘地理解为对父类方法的重载,使得同一个方法拥有不同的参数列表。我觉得多态才是面向对象的精髓,在我的坦克程序中,有个控制规则的类,这类里面有一个方法需要一个参数,这个参数可能是坦克类,也可能是子弹类,不确定,需要调用它们的move()方法,当然可以用强大的重载功能去重载这个方法如:someFun(tank mObj){….};重载一下someFun(zidan mObj){….};貌似除了把mObj这参数的类型换了下,其他都没动。但确实解决了这问题。如果这个变态的方法实现是10000行,一重载2万行了。如果以后出现飞机这个类也有move方法,那还要再重载一次。使用继承+接口就简单的多了,只需要写一个叫做ImoveObj的接口里面定义一个move方法,这个接口被坦克,子弹,飞机类继承下,把方法写成someFun(ImoveObj mObj){….};以后无论增加多少可以充当mObj这个参数的类,只需要继承下ImoveObj接口便可。(用过工厂模式的,觉得这个太司空见惯了。确实,不过这也是多态的基础理解。)
封装:这个也好理解,使用一个类只需要知道这个类的方法怎么用即可,不需要知道这个方法的具体实现。接口是开发者的设计说明书,开发者去实现接口里面的东西。接口也是使用者的说明书,告诉类的使用者此类实现了什么方法,只要会用即可无需了解其实现。
虽然都是些简单的基础,但只有完全理解了这些东西再去研究注入,反转,映射等等不会那么吃力了。
除了面向对象还有面向接口,面向方面(切面)等,无论用什么思想去编程最核心的还是算法,小到一个函数,都离不开算法。
编程最重要的是思想,技术决定能力,而思想决定能力的深度。