个人学习杂谈&java抽象杂谈

在时隔一年多重新开始写博客后,我翻阅了一下以往写的博客,发现了一个非常神奇的事情——我的博客可读性真的不强!这兴许是因为我在写博客的时候并不花太大的力气去组织语言,通篇写的有点流水账;但另一方面,或许是我在写博客的时候,总是只把我自身最新的理解给写下来,并不考虑读者的知识基础是否恰好可以读懂。由于我的博客是以源码阅读、设计模式等内容为主的,所以这篇文章简单谈一谈我在java的设计、抽象等方面的一点体会。

最近我在很多场合下,与有许多人在学习方式、架构思想等方面有过一些讨论,由此回顾在开发上的整个学习历程,也有一些浅显的感悟,在此一并说了。

特别提示,这是一篇总结型而非技术型的博客,如果是着急获取知识的读者,就不要继续阅读以免浪费自己的时间了!

在这个信息化的社会,学习的方式可谓是多种多样,各类博客、教程、视频以及开源代码成为了不少码农们学习的核心手段,书本学习在一定程度上已经渐渐暗淡,虽然大部分程序员也会阅读一定量的书籍,以求知识体系的健全,但是在书本的选择上,越来越多的人趋向于生动易懂的书本,而放弃一些较为经典的书籍。

这显露出一个非常严峻的事实,大家在学习中,夹杂着一种急于求成的浮躁,因此总是选择能够快速摄取知识的学习方式,但是这里我不得不提出一个问题——学习,究竟是为什么而学习的?知识?还是能力?

大学的时候,我曾经在和一个学弟的谈话中听到了这么一句话“我们学习不就是为了获取知识嘛,至于怎么获取的这个知识,真的重要嘛?”,这位学弟有一些自己的体会,我尊重他的想法,但是在这里我想说的是,我个人并不认为学习是在单纯地获取知识,假若只是获取知识,我们为什么还要在大学期间,在别人都在吃鸡lol的时候认真学习呢?只需要花几个月时间报个培训班也同样可以获取知识呀?

在有的时候,学习或许确实是为了获取知识,比如当你有个问题需要快速做修改的时候;但是在更多的时候,学习应该是以个人能力的培养为目的的,“自己已经不再是以前的自己了,知识只是副产品罢了!”

吾生也有涯,而知也无涯,以有涯随无涯,殆矣!

庄子这话八面玲珑,对不同的人与事亦是吹万不同,但是这话放在知识日新月异的IT界,却是一点都不唐突。我相信在这世上没有哪个程序员可以说“IT方面所有知识,我都懂!”,大家在遇到棘手的问题时候,依旧需要依赖于互联网查找解决方案,如果只从知识的层面来看待问题的话,程序员之间岂非丝毫没有任何差别了?反正百度谁都会用嘛!然而对问题的一种潜意识的感觉,对寻找解决方案的一种敏锐的嗅觉,却不是知识量所能解释的了的。

当然,我并非说知识或者知识量不重要,相反个人知识量是非常重要的。知识可以成为能力的一部分或者成为提高能力的一个可靠途径。但是,至少我认为,不能把知识当做能力的全部。

相信不少人在初学阶段遇到一些比较坑的问题的时候会觉得十分郁闷甚至暴跳如雷,这是人之常情,因为无论怎样,这个看似并不能对你的知识量起到多大帮助的问题占用了你大量的时间。“如果你在学习中连解决不了的问题都遇不到,你的能力如何提高呢?”,这是我IT技术的授业恩师曾经说过的话,我对此记忆犹新(大体意思是这样,语言组织可能并不完全相同),同样也是由于他在学生学习方式上的一些执着,让我一度对学习方式上有较多的思考。我不认为我是个能力出众的人,在知识量上也完全是个初学者的水平,但是我相信在学习方式上做的思考,我应该超过了半数的程序员。

诚然,博客、教程可以帮助人们快速获取知识,下载例程阅读可以帮助人们快速上手,生动的书籍可以帮助人们快速地理解一些晦涩难懂的知识,这些学习方式在当今快节奏的工作状态下是不可或缺的手段,但是这并不能成为学习的全部,当自己通过各种快速学习的手段获取的碎片化的知识达到一定程度的时候,静下心来,仔细阅读一本值得推敲的经典的书籍,或许会得到一些不一样的体会,而这些体会,与你经历产生的作用,才是你自己的知识宝库。即便这本书十分晦涩难懂,但“经读百遍,其义自见”,将一本好书成为长期的学习参考,当彻底将这本书嚼烂的时候,无论你的知识量、对于该领域的深刻体会、或是自身的能力,都会得到极大的提高。

而《设计模式》一书可谓是一个非常好的例子了,在我前面写的博客中,大概有那么两三篇水水地提过具体的设计模式,但是说的较为浅显,很多时候也就是照抄书上的例子,或是给出自己碰到的一些典型的可以说明某种模式的案例,但是从未去系统整理过设计模式,一方面,这是由于个人能力尚有欠缺;另一方面,也是设计模式本身有他知识性质的独到之处。

设计本身就是一个非常主观的事情,你可以说一个好的设计比一个不好的设计要好得多,但是你很难判断两个同样不错的设计谁更好。千古文人相轻,而设计也和文学类似,一个设计的好坏,需要取决于此情此景下是否能改善遇到的问题,这还不尽然,即使完全相同背景下两个不同的设计,也很难衡量好坏。常有程序员觉得他人的设计十分糟糕,却未曾仔细体会过他人设计的初衷。一个好的架构设计师应该有对他人设计的足够的包容心,在仔细体会他人设计缘由后再提出自身的意见;同样一个好的架构设计师也应该能包容他人对自己设计的不尊重。这并非是单纯地学术理论,而是软件设计的事实,这世上没有最好的设计,举个极端例子:几乎所有的软工著作都提倡过程调用,因为这可以让功能更加模块化,但是如果你仔细读一本涉及系统底层知识的书籍就会发现,这些书提出了几乎完全相反的建议,因为过程调用会增加系统性能的开销。不同设计的利弊原本就是需要开发人员自己去权衡的,并没有标准的答案。

如果将写代码比作行军打仗,那么设计就是兵法,《设计模式》就是一部兵书。你可以通过熟读兵书来通晓兵法,也可以通过一些对这本兵书的解读(G4发布《设计模式》后其他人所著各类设计模式的书籍)来更加直观易懂地了解兵法,但是没有实战经验,一切的精通都是纸上谈兵。相反,如果你拥有相当量的实战经验,此时静下心来细读一部兵书,一种感同身受的体会就会油然而生,此时若能受到某一事某一言的刺激,愈来愈多的体会直至融会贯通,未来设计岂非得心应手?我曾经在给低年级研究生面试时候提问“什么叫做面向对象?”,结果发现回答不是支支吾吾就是极为官方(封装、继承、多态云云),虽然官方回答并不算错,但是我认为能说出自己体会的才是真正了解面向对象的人,真若融会贯通的,自己给出两句定义又如何?“大海中泛出一点浪花罢了”。

但即使当真达到如此也不要过分狂傲自骄,如我前文所说,设计本身就是个利弊权衡的事情,如同战场上没有哪种阵势是真正所向无敌的。战场上排兵布阵的最终方案由主帅决定,属下即使有更为优秀的方案(大多数是自认为优秀),也只得建议,而不能违抗命令,自乱阵脚者必败。设计上亦是如此,即使你拥有很强的设计能力,也必须遵循项目整体的设计规范,除非你是系统的首席架构,并且系统正处于重构阶段,否则胡乱违背系统整体规范而使用自己的设计理念,只会让代码变得更加晦涩难懂。

说到规范,不知大家是否想过,为何java能作为一种承载大体量工程核心架构的语言?论效率不如c、c++,论方便不如js、php,虽然有着类库众多的优势,但是与近几年的语言黑马python相比倒也有些暗淡,何况类库众多本身不也是由于语言本身存在某种优势,才会有众多的开发人员投入智慧与经历,生成各种开源第三方的框架与类库嘛?

规范,依然是规范,我认为java最大的优势就是其几乎渗透到各个角落的规范。事实上在我接触到的所有语言中,java的语法应该算是最为规范的了:变量必须定义类型(这里不考虑泛型)、参数必须写明(这里不考虑可变参数的写法)、代码必须以类的结构去定义。。。。诸多的规范,外加java本身将报错分发给编译(Error)和运行(Exception)以及JVM对垃圾处理的一些机制,造就java本身容错性上的强大。在一个大型项目开发过程中,多名程序员之间的协调必须以规范作为约束,而如果语言本身就有很强的规范,那他自然就天生具有承载大体量项目的优势了。

说到java的规范,又不得不提一下一个名为接口的东西。对于一个java开发人员来说,接口应该是一个熟悉的不能再熟悉的名词了。接口这个概念究竟是谁最先提出的,我不清楚,但是接口这个词汇被用的最多的,至少再软件开发的世界中,当属java程序了。其实初学java的时候我觉得很奇怪,为啥接口要叫接口呢?按类族来观察,接口应该是最上面,作为类族老祖宗的存在,为啥取了个好像在最外面的名词——接口,呢?

为什么华硕的电脑可以连接戴尔的显示器?因为他们都有VGA、HDMI接口。接口,这个名词本身象征着规范,接口的两端都遵循这个规范,因此即使毫不相干的开发者开发出的东西也能轻而易举的结合。而对于java中的接口而言,接口的两端,自然就是接口的实现和接口的调用了。调用者和实现者往往由不同的人去开发,而大家都遵循接口中原本做好的定义,因此,不同的开发人员的代码才可以简简单单的互相调用,而这个接口的定义者,或是公司内部的架构师,或是IT社区最具权威的公司或机构,因此才有了“一流公司写接口,二流公司写实现。”这样的话。

规范兴许是件好事,但是在某些时候却是一件不怎么方便的事情,因为这可能会造成不可避免的代码重复。因此,才有了java中一些动态化的语法:泛型、反射、注解。而这三者中,最具核心地位的,自然就是几乎所有框架都会用到的反射机制了。

刚刚说过了,接口分离了调用和实现,而如果让我用一句话概括反射就是:动态调用+动态实现。java中,调用包含了初始化、执行方法、获取内部变量等等,而当你无法准确写下调用的具体内容的时候,当你需要通过一些字符串等等的标记去让代码动态调用的时候,反射自然是首当其冲的选择(具体用法不提了);而当你的接口的实现并不确定的时候,java的动态代理(也在java.lang.reflect包下)则是最好的选择(mybatis、spring的AOP、dubbo等等都是如此实现的)。而泛型则主要抽象了变量类型的定义,其主要目的是避免了强制转换。至于注解,则是作为一种标记的方式,在反射过程中作为一种判断条件。

至此,我对于java的接口、动态、抽象的主要理解就基本说完了,学识有限,如果读者有不同的意见也欢迎探讨。接下来的细节都是对这些概念的具体实现和应用,不在本文范畴内。而反射也恰好可以成为设计的利弊权衡理念的一个重要标准。反射动态了抽象了实现,但是抛弃了规范,让原本在编译过程中就可以抛出的error变成了只有在运行过程中才会产生的exception。这种利弊两面性,则对于程序员在使用反射时候权衡的一个更高的要求。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章