我們內部每周都有讀書會,最近在讀《clean code》,基本上是20分鍾左右。總體原則是大家輪流來講。 我自己也領了其中一章,第八章。這一張特別不巧,書少了3頁。整個一章少了一半的內容。於是我自己發揮了一下,希望大家能有所收獲。
從接口到類、工程、系統、框架。在做設計的時候關於邊界的基本思路是一致的。就是需要在普適性和集中性中做一個權衡。權衡的結果直接就影響着邊界。
邊界的目的是要保證:易於理解,難以被誤用。
邊界划分的典型例子:spring
spring框架是一個分層架構,由7個定義良好的模塊組成。每個模塊都可以單獨存在,或者與其他一個或多個模塊聯合實現。
- 核心容器:核心容器提供Spring框架的基本功能。核心容器的主要組件是BeanFactory,它是工廠模式的實現。BeanFactory使用控制反轉(IOC)模式將應用程序的配置和依賴性規范與實際的應用程序代碼分開。
- Spring上下文:Spring上下文是一個配置文件,向Spring框架提供上下文信息。Spring上下文包括企業服務,例如JNDI、EJB、國際化、校驗和調度功能。
- Spring AOP:通過配置管理特性,Spring AOP模塊直接將面向方面的編程功能集成到了Spring框架中。所以,可以很容易的使Spring框架管理的任何對象支持AOP。Spring AOP模塊為基於Spring的應用程序中的對象提供了事務管理服務。通過使用Spring AOP,不用依賴EJB組件,就可以將聲明性事務管理集成到應用程序中。
- Spring DAO:JDBC DAO抽象層提供了有意義的異常層次結構,可用該結構來管理異常處理和不同數據庫供應商拋出的錯誤消息。異常層次結構簡化了錯誤處理,並且極大的降低了需要編寫的異常代碼數量(例如打開和關閉連接)。Spring DAO的面向JDBC的異常遵從通用的DAO異常層次結構。
- Spring ORM:Spring框架插入了若干個ORM框架,從而提供了ORM的對象關系工具,其中包括JDO、Hibernate和iBatis SQL Map。所有這些都遵從Spring的通用事務和DAO異常層次結構。
- Spring Web模塊:Web上下文模塊簡歷在應用程序上下文模塊之上,為基於Web的應用程序提供了上下文。所以,Spring框架支持與Jakarta Struts的集成。Web模塊還簡化了處理多部分請求以及將請求參數綁定到域對象的工作。
- Spring MVC框架:MVC框架是一個全功能的構建Web應用程序的MVC實現。通過策略接口,MVC框架便成為高度可配置的,MVC容納了大量視圖技術,其中包括JSP、Velocity、Tiles、iText和POI。
明確的職責是整潔邊界的基礎。拿Spring的核心容器舉例。從上面圖中可以看出,核心模塊是spring框架中最底層核心的模塊,提供了最基本的IoC思想和一些核心工具。想明確邊界先要明確概念和職責。
IoC
IoC是Inversion of Control的縮寫,多數書籍翻譯成“控制反轉”。是1996年,Michael Mattson在一篇有關探討面向對象框架的文章中首先提出來的。簡單來說就是把復雜系統分解成相互合作的對象,這些對象類通過封裝以后,內部實現對外部是透明的,從而降低了解決問題的復雜度。
IoC的別名:依賴注入(DI)
2004年,Martin Fowler討論了既然IoC是控制反轉,那么到底是哪些方面的控制被反轉了呢?經過詳細地分析和論證后,他得出了答案:“獲得依賴對象的過程被反轉了”。控制被反轉之后,獲得依賴對象的過程由自身管理變為了由IoC容器主動注入。於是他給“控制反轉”取了一個更合適的名字叫做“依賴注入(Dependency Injection)”。他的這個答案,實際上給出了實現Ioc的方法:注入。所謂依賴注入,就是由IoC容器在運行期間,動態地將某種依賴關系注入到對象之中。所以,依賴注入和控制反轉是從不同的角度來描述同一件事情,就是指通過引入IoC容器,利用依賴關系注入的方式,實現對象之間的解耦。
到現在spring core的核心邊界已經可以確立了。那么再進一步從實現上來剖析邊界。
IoC中最基本的技術就是反射。通俗來講就是根據給出的類名來動態的聲稱對象。這種方式可以讓對象在生成時才決定到底是哪一種對象。
IoC容器的工作模式可以看做升級版的工廠模式。然后利用編程語言 的反射編程,根據配置文件中給出的類名生成相應的對象。從實現來看,IoC是把以前在工廠方法里寫死的對象生成代碼,改變為由配置文件來定義,也就是把工廠和對象生成這兩者獨立開,目的就是提高靈活性和可維護性。
好,現在技術實現的主要思想也清晰了。這樣在代碼分層上會有一個大體的思路,超出邊界的設計不會太多了。下面就來具體看看代碼。
spring core的工程下面,分為6個package,分別是asm,cglib,core,lang,objenesis和util。
ASM是一個全功能Java字節碼操作與分析框架。可以用來修改已有的class文件或者直接以二進制形式動態生成class。它提供了通用轉換與分析算法,自己組合復雜轉換與代碼分析工具。
CGLIB是一個強大的、高性能的代碼生成庫。主要通過對字節碼的操作,為對象引入簡介級別,以控制對象的訪問。
objenesis本身也是一個強大的java庫,主要是用在創建對象上面。它可以不用調用構造函數就創建對象。專門用於實例化一些特殊java對象,如私有構造方法,帶參數的構造等不能通過class.newInstance()實例化的。
前三個都是反射的實現方式。
lang大家都很熟悉了,是language的縮寫,定義了使用的語言,這里具體指JVM。
core包里具體實現了IoC。
util包提供了核心工具,基本上就是對象的生成工具,因為IoC的核心作用就是生成對象。
代碼大體框架的邊界也定義出來了。下一步看接口。時間關系看最簡單的lang包的。
四個注解接口
public @interface UsesSunHttpServer {
}
public @interface UsesJava7 {
}
public @interface UsesJava8 {
}
public @interface UsesSunMisc {
}
從接口定義就可以看到這是非常符合這個包的職責的。
再往下具體實現類我就不講了,主要給大家提供一種思路,整潔的邊界是怎樣定義出來的。先要從大局上想清楚,然后是一個整體的設計,雖然應用程序的代碼天然封裝好了設計模式,但是這種理念需要有,這會非常利於寫出整潔的代碼。代碼層次天然表達了設計思路,有人說代碼即注釋,我看來代碼即設計。好的代碼會像好的設計文檔一樣讓人讀着舒服。
另外,我選用spring框架代碼來說明代碼整潔之道,主旨在於我個人覺得要寫好代碼,持續的去了解自己使用的框架、底層源碼是一個應該形成的習慣與基本功。因為只有去不斷的反思這些東西做了什么才能更好的用好它。我自己親身感受的學習思路是先學其所長,然后再自成一派。而寫好代碼又和寫好文章非常類似。我最喜歡舉得學好之后自成一派的例子就是古龍,總在開場讓人驚艷一把。
很多他的開場白讓人過目不忘。比如我現在還記得《天涯明月刀》的開場白:
“天涯遠不遠?”
“不遠!”
“人就在天涯,天涯怎么會遠?”
“明月是什么顏色?”
“是藍的,就像海一樣藍,一樣深,一樣憂郁。”
“明月在哪兒?”
“就在他的心,他的心就是明月。”
“刀呢?”
“刀就在他手!”
“那是一柄什么樣的刀?”
“他的刀如天涯般遼闊寂寞,如明月般皎潔憂郁,有時一刀揮出,又仿佛是空的!”
“空的?”
“空空蒙蒙,縹緲虛幻,仿佛根本不存在,又仿佛到處都在。”
“可是他的刀看來並不快。”
“不快的刀,怎么能無敵於天下?”
“因為他的刀已超越了速度的極限!”
“他的人呢?”
“人猶未歸,人已斷腸。”
“何處是歸程?”
“歸程就在他眼前。”
“他看不見?”
“他沒有去看。”
“所以他找不到?”
“現在雖然找不到,遲早總有一天會找到的!”
“一定會找到?”
“一定!”
好,就用古龍的風格總結一下我記住的前八章的《clean code》的內容:首先,要有意義的命名 。其次,格式很重要。然后,代碼也有思想流派。最后,整潔代碼是藝術。
總結與思考:
我來現在的公司是因為意識到自己格局的問題。之前我看的視野太窄,所以我有強烈的需求想看到更全局性的東西。結果,我卻忽視了一個更加顯而易見的東西:角度。我所站的角度才更反映我的格局。
長久以來,我總是覺得我代表我個人。我最得意的事情從來不是工作上的成就,而是我是一個好妻子,好媽媽,好女兒,好兒媳。我不在乎別人怎么看我,因為我相信我自己,知道一切都會好起來。但是在工作中,我代表更多的是一個集體。代表集體不是簡單的從用詞的我變成我們。而是我每一個決策給集體帶來什么樣的影響。我遇到事情,我應該找集體來商討,而不是覺得自己可以就可以做出決定。
跑題時間:
無題1
千辛萬苦,
千思萬緒,
淡然一笑,
默默無語。
感激並懷恨着,
讓我變得如此強大的那個人
無題2
如果注定是擦身而過,不要回頭;
哪怕比痛更痛,以后的路都了無生趣,心如死灰;
不回頭至少記憶里是笑容;
回頭他會看到一雙含淚的眼睛