譯文作者:意識
資訊來源:邪惡八進位資訊安全團隊(www.eviloctal.com)
某天在某一家軟體公司裡,那令人討厭的專案經理要求兩名程式員完成同樣的一個任務。經理並且承諾誰先完成任務的發給一張帶轉輪的真皮沙發代替原來的木質靠背椅。傑習慣過程式編程的程式員,而濤是一個物件導向的程式員。他們都知道這是一個不錯的機會。
任務是這樣的,在GUI的程式介面裡有一個正方形,一個圓形和一個正三角形。但使用者點擊這個圖形時,圖形會順時針旋轉360°並且播放相應的AIF音效。
傑,坐在自己的辦公室裡,對自己說:“這個程式要做什嗎?我們需要那些過程?”“旋轉並且播放音效。”他又回答了自己。所有他的程式就是去完成這兩個過程。
濤帶著他的筆記本坐在休息室裡。他也在思索著:“程式中都有什麼東西啊?誰是主要的角色啊?他最先想到的就是形狀。當然他也想到了其他的一些對象,比如使用者,音效和點擊事件。因為已經有現成的庫支援其他的對象了。因此因此他把重點放在建立形狀類上。
在傑的辦公室
就像曾經寫過千百的的程式一樣,傑把他的程式認為是重要的過程,並且沒有用什麼時間就完成了旋轉和播放音效的過程。他的程式大概是這樣的
rotate (shapeNum) {
// make the shape rotate 360°
}
playSound (shapeNum) {
// use shapeNum to lookup which AIF sound to play, and play it
}
濤和他的筆記本在休息室
濤為每個形狀寫了一個類
class Square {
rotate () {
// code to rotate a square
}
playSound() {
// code to play the AIF file for a square
}
}
class Circle {
rotate () {
// code to rotate a circle
}
playSound() {
// code to play the AIF file for a circle
}
}
class Triangle{
rotate () {
// code to rotate a triangle
}
playSound() {
// code to play the AIF file for a triangle
}
}
傑的程式基本是完成了,他覺得他贏了,他似乎已經感覺到那張真皮沙發了。
但是請等一下,任務有所變動
“現在你是快一點,傑”,專案經理說著,“但我還要加一點小小的功能在程式裡。這對你們這樣高水品的程式員來說,應該是毫無問題的。”
“如果只是個小改動,我可以接受。”傑想著,他知道經理所說的毫無代價的改動是胡扯。“為什麼濤會顯得如此的平靜呢?”傑不解得想著。傑一直執著認為物件導向只是個花架子,完全是浪費時間。
新增的任務
在GUI介面裡多了一個不規則圖形,當使用者點擊該個圖形時,圖形也會旋轉360°,並且播放一個 .hif的音效。
傑回到辦公室
旋轉的過程依然時可以用的,因為代碼使用的是shapeNum來對於相應的圖形。然而播放音效的過程需要修改。“為什麼非要播放 .hif的音效呢?”,傑憤憤的說著。
playSound (shapeNum) {
// if the shape is not an amoeba,
//use shapeNum to lookup with AIF sound to play, and play it
//else
//play amoeba .hif sound
}
這不是一個很大的改動,但是傑依然不得不重新修改他已經調試成功過的代碼。
濤在他的筆記本前
濤微笑著,呷了一口茶。隨手寫了一個新的類。有時他覺得他最喜歡物件導向中的這個優點,就是對已經編譯調試過的代碼可以不要任何改動。靈活和課擴充形……,濤沉醉在物件導向的優點中了。
class Amoeba{
rotate () {
// code to rotate an amoeba
}
playSound() {
// code to play the new .hif file for an amoba
}
}
傑這一次只比濤領先一步
“物件導向都是在胡扯,浪費時間!”傑正在暗笑著濤。“不規則圖形不是這樣旋轉的。”
專案經理失望的說。
原來,傑和濤都是這樣寫的
用一個矩形圍住不規則圖形,然後計算矩形的中心,最後讓圖形以中心旋轉。
專案經理接著說:“它應該以一個給定的座標旋轉。”
“我真像是一塊砧板上任人宰割的肉。”,傑想著“但我可以再加上一些if…else 語句就可以搞定了。”然而天知道經理會又有什麼改動呢?
傑的辦公室
他思索著旋轉的過程。很多的代碼受到影響的。傑又要重新編譯調試。終於有了結果。
rotate ( shapeNum, xPt, yPt) {
// if the shape is not an amoeba,
//calculate the center point base on the rectangle, the rotate
//else
//use the xPt and yPt as the rotation point offset an the rotate
}
濤在他的筆記本前
為了不把沙發拱手讓給傑,濤也在修改他的旋轉方法,但僅僅是在Amoeba的類裡。對於其他的測試好的類,是原封不動的。為了給不規則圖形一個旋轉點,他給Amoeba加肋兩個屬性,然後他測完成後通過無線網路提交了任務。
class Amoeba{
int xPoint;
int yPoint;
rotate () {
// code to rotate an amoeba using amoeba’s x and y
}
playSound() {
// code to play the new .hif file for an amoba
}
}
那濤得到了沙發對嗎?
並沒有那麼快,傑找到濤程式裡的一個缺陷。並且他知道如果能得到沙發的話就可以取悅會計室的婷,因此他不希望就這樣就輸了。
下面是傑和濤的對話
傑:你的代碼大量重複,你的旋轉過程在四個圖形的東西裡都有。
濤:這是方法,不是過程。還有他們是類,不叫做東西。
傑:不管叫什麼,你的設計簡直是垃圾。你要處理四個不同旋轉“方法”。你怎麼處理啊?
濤:我猜你是沒看見最後的設計。讓我告訴你繼承在物件導向中書如何工作的。看這四個類是有共同點的。它們都有rotate()和playSound()
於是我抽象出一個Shape類來
abstract class Shape(){
rotate();
playSound();
}
然後我讓這四個類繼承這個抽象的類
class Square extends Shape {
rotate () {
// code to rotate a square
}
playSound() {
// code to play the AIF file for a square
}
}
class Circle extends Shape {
rotate () {
// code to rotate a circle
}
playSound() {
// code to play the AIF file for a circle
}
}
class Triangle extends Shape {
rotate () {
// code to rotate a triangle
}
playSound() {
// code to play the AIF file for a triangle
}
}
class Amoeba extends Sharpe{
int xPoint;
int yPoint;
rotate () {
// code to rotate an amoeba using amoeba’s x and y
}
playSound() {
// code to play the new .hif file for an amoba
}
}
那Amoeba的類旋轉呢?
傑:問題不是就在這嗎?Amoeba有完全不同的旋轉和播放音效的過程嗎?
濤:是方法。
傑:不管是它叫什麼了。Amoeba怎麼能實現與他說繼承的類shape不同的事呢?
濤:這是最後一遍了。Amoeba重騎(overrides)了Shape類的方法。在運行時(runtime)Java的虛擬機器(JVM)知道但程式需要Amoeba去旋轉時應該調用相應的方法。
傑:你怎麼告訴Amoeba去旋轉啊?難道你們不要調用過程,哦不對,是方法然後告訴它應該那個圖形去旋轉嗎?
濤:這就是物件導向的好處所在了。比如說,要讓三角形旋轉。程式調用Triangle對象的rotate( )方法。程式的其他部分不知道也不在於三角形形是怎麼轉的。當你要想添加一點功能到程式中時,你只要寫一個為新的物件類型寫一個新的類,那個新的對象有自己的特性。
傑:我希望我也能成為一個物件導向的程式員,這太神奇了。