用費曼技巧學編程,香不香?

引子

 有一本講諾貝爾獎得到者,物理學家費曼的書,叫作《發現的樂趣》,書中寫到一個費曼小時候的故事:java

 「咱們家有《大不列顛百科全書》,我仍是小孩子的時候,父親就經常讓我坐在他腿上,給我讀些《大不列顛百科全書》。好比說,咱們讀關於恐龍的部分,書上可能講雷龍或其餘什麼龍,書上會說:「這傢伙有 25 英尺高,腦殼寬 6 英尺。」 程序員

這時父親就停下來,說:「咱們來看看這句話什麼意思。這句話的意思是:假如它站在咱們家的前院裏,它是那麼高,高到足以把頭從窗戶伸進來。不過呢,它也可能遇到點麻煩,由於它的腦殼比窗戶稍微寬了些,要是它伸進頭來,會擠破窗戶。 編程

費曼說:凡是咱們讀到的東西,咱們都儘可能把它轉化成某種現實,從這裏我學到一個本領——凡我所讀的內容,我總設法經過某種轉換,弄明白它究竟什麼意思,它到底在說什麼。框架

 

費曼技巧

 

費曼技巧,或者說費曼學習法是一種以教促學的方法,一共有四步(已經知道的能夠無視,直接跳過): 編程語言

(1) 選擇新概念/新知識, 本身先去學習它。 微服務

(2) 僞裝當一個老師,去教授別人 學習

想象你面對一羣小白,怎麼把這個概念講給他們聽,讓他們理解呢? this

把你講解的思路也寫到紙上,若是實在不想寫,能夠說出來。 spa

很是重要!!!不要讓你的思路停留在大腦中,由於大腦中對於知識點之間的關聯會有些想固然的、錯誤的假設,說出來或者寫出來能找到這些「盲點」!!線程

 

(3) 若是你在教授的過程當中遇到了麻煩,卡了殼,返回去學習。 

從新去看書,搜相關資料,問別人,倒逼本身把這個概念搞清楚, 而後回到第二步,繼續給小白講授。

 

(4) 簡化你的語言。 

目標是用你本身的語言,非專業的詞彙去解釋這個概念。儘可能作到簡單直白,或者找到比喻來表達。 

很是簡單的過程,對吧? 

 

實戰演練

咱們來用個例子來演練一下,有請碼農翻身頭號主人公張大胖出場。 

張大胖正在學習Java,這一天他遇到了一個新的概念:「動態代理」  (注意是學習這個概念,不是具體實現), 很是抽象,在平常編程中幾乎不會直接使用,理解起來有難度。

 

第一步,自學

 張大胖看了動態代理的介紹,書上列舉出一堆煩人的代碼來展現這個東西是怎麼使用的,好比有個接口(IHelloWorld)及其實現類(HelloWorld), 而後有個InvocationHandler的實現,最後用Proxy.newProxyInstance(....)建立一個新的類出來,這些都是什麼鬼?囉裏囉唆的。

 

第二步,張大胖嘗試教一下小白(固然這裏的小白至少得懂點兒Java)

 

張大胖:動態代理嘛,很簡單,就是給定一個接口和實現類,再加上一個InvocationHandler , 動態代理這個技術能夠在運行時建立一個新的代理類出來。 

小白:張老師, 新的代理類有什麼用? 

張大胖:舉個例子,有個叫IHelloWorld接口及其實現類HelloWorld,它有一個叫sayHello()的方法。能夠在sayHello()以前和以後,額外加一些日誌的輸出。 

(在講解一個概念的時候,舉例和類比很重要,人類習慣於經過例子來學習,從具體走向抽象) 

小白:那我直接寫一個新的類,好比HelloWorldEx,把日誌輸出添加到其中不就好了,爲何還要用Proxy.newProxyInstance(......)這麼麻煩的方法?

public class HelloWorldEx implements IHelloWorld{
    IHelloWorld hw;
    public HelloWorldEx(IHelloWorld hw){
        this.hw = hw;
    }    
    public void sayHello(){        
        Logger.startLog();
        hw.sayHello();
        Logger.endLog();
    }
}

  

張大胖沒法回答這個問題,卡殼了! 

第三步,回過頭去看書,學習。

書中也沒有解釋,唉! 

仔細想想,手動寫一個類HelloWorldEx和用Proxy.newProxyInstance來建立,區別究竟是什麼? 

實現的功能是相同的,可是HelloWorldEx須要事先寫好,編譯後不能改了,至關於寫死了!若是我想對Order類,Employee類,Department類,也想加點兒日誌,還得寫個OrderEx,EmployeeEx,DepartmentEx的類,太麻煩了! 

而Proxy.newProxyInstance這種方法,能夠在程序運行的時候爲任意類動態地建立加強的類。 

事先寫死的叫作靜態代理,Proxy.newProxyInstance這種方式叫作動態代理,更加靈活。 

張大胖以爲這麼解釋就通了。 

小白:爲何要建立新的代理類,那個Proxy.newProxyInstance不能直接修改老的HelloWorld類嗎? 

張大胖再度卡殼,上網搜索,找到了答案,和Python,Ruby等方法不一樣,Java本質是一個靜態類型的語言,class一旦被裝入JVM,是不能修改,添加,刪除方法的,既然老的class不能修改,只能經過代理的方式來建立新的類了。 

小白:懂了,這個技術主要用在什麼地方啊? 難道只是加個日誌? 

張大胖第三次卡殼,只好再次搜索。 

原來動態代理使用得最多的是AOP,AOP中常常會以聲明的方式提出這樣的要求: 

某個包下全部add開頭的方法,在執行以前都要調用Logger.startLog()方法,在執行以後都要調用Logger.endLog()方法。 

或者對於全部以Service結尾的類,全部的方法執行以前都要調用tx.begin(),執行以後都要調用tx.commit(), 若是拋出異常的話調用tx.rollback()。

 

到此爲止,張大胖能夠這樣來給小白講述了: 

你不是用過Spring AOP嗎?AOP中常常有這樣的需求......  ,Spring想添加這些日誌和事務的功能,可是卻沒有辦法去修改用戶的類,它是框架啊,一是不知道用戶類的源碼,二是Java不容許再修改裝載入JVM的class。 

沒辦法,Spring只好在運行時找到用戶的類,而後操做字節碼動態建立一個新類,新類會對原有的類進行加強,添加日誌,事務這些功能,注意啊,這些都是在內存中動態建立的。 

這個技術就是Java的動態代理,不過它有個前提要求,就是用戶的類須要實現接口才行。我用一個簡單的例子給你說下,你就明白細節了......

 

第四步,簡化,比喻

上面的講解從文字上來講仍是很是囉嗦的,用了很大篇幅來說解「爲何」,由於理解了why ,剩下的就是細節了。  

若是你完全理解了之後,動態代理的技術細節會在大腦中會創建這麼一幅圖景:

 

$HelloWorld100就是那個代理類,它和HelloWorld都實現了IHelloWorld這個接口。 

若是必定要用個比喻來講,它們倆就是「兄弟關係」,CgLib提供了另一種對現有類加強的辦法,動態生成的類繼承了現有的類,二者是「父子關係」。

  

小結

 怎麼樣?用這種(僞裝)教授別人,層層遞進、自我逼問的方法是否是頗有效果?收益很大?  

用這種辦法,實際上就是逼着你把大腦中的盲點和一些想固然的假設給暴露出來,效果要比單純地閱讀和記憶好得多,趕忙在學習中試一下吧!

  

更多精彩文章,盡在碼農翻身

 

我是一個線程

TCP/IP之大明郵差

一個故事講完Https

CPU 阿甘

Javascript: 一個屌絲的逆襲

微服務把我坑了

如何下降程序員的工資?

程序員,你得選準跑路的時間!

兩年,我學會了全部的編程語言!

一直CRUD,一直996,我煩透了,我要轉型

字節碼萬歲!

上帝託夢給我說:一切皆文件

Node.js :我只須要一個店小二

相關文章
相關標籤/搜索