天天看點

《面向對象設計實踐指南:Ruby語言描述》—第1章 1.1節設計贊歌

本節書摘來自異步社群《面向對象設計實踐指南:ruby語言描述》一書中的第1章,第1.1節設計贊歌,作者【美】sandi metz,更多章節内容可以通路雲栖社群“異步社群”公衆号檢視。

第1章 面向對象設計

面向對象設計實踐指南:ruby語言描述

世界是過程式的。時間不停在向前流動,而事件也一個接一個地逝去。你每天早上的過程或許就是:起床、刷牙、煮咖啡、穿衣,然後上班。這些活動都可以使用過程軟體來模組化。因為了解事件的順序,是以你可以編寫代碼來完成每一件事情,然後仔細地将這些事情一個接一個地串在一起。

世界也是面向對象的。與你互動的對象可能包括有你的老伴和貓,或者是車庫裡的舊汽車和一大堆的自行車零件,又或者是你的那顆撲通跳動的心髒,以及用來保持健康的鍛煉計劃。在這些對象中,每一個都擁有它們自己的行為,而且它們之間某些的互動可能還是可預測的。例如,你的老伴意外地把貓給踩了一下,進而引起一個激烈的反應,大家的心跳頻率都迅速升高,同時也為你增添了一種新的鍛煉方式,這是完全可能的。

在由對象構成的世界裡,新的行為編排在很自然的情況下便會出現。你不用顯式地為“老伴踩貓”這一流程編寫代碼,而你所需要的是這樣兩個對象:一個會擡腳的老伴和一隻不喜歡被踩的貓。把這兩個對象一起放到一個房間裡,行為的意外組合便會出現。

本書與面向對象軟體的設計有關,它将世界看作是對象之間一系列的自然互動。面向對象設計(ood)要求你從認為世界是由一組預定義過程構成的觀念,轉變至認為世界是由多個對象之間的一系列消息傳遞構成。ood的失敗看起來很像是編碼技術的失敗,但它們實際上是視角的失敗。學習如何進行面向對象設計的第一個要求便是要讓自己沉浸在對象之中。一旦你采用面向對象的視角,那麼其餘部分也會水到渠成。

本書将通過沉浸式的過程給你指導。本章一開始會對ood進行一般性的讨論。它首先是讨論設計的情況,接着會描述何時進行設計以及如何對它進行評判。在本章的結尾是對面向對象程式設計的概述,它定義了全書所用的術語。

1.1 設計贊歌

軟體被建造出來總有它的原因。目标應用程式是全部的重點。無論這個程式是微不足道的遊戲,還是要被用于指導輻射療法,都一樣。如果程式員們認為痛苦的程式設計工作就是以低成本方式生産工作軟體,那麼他們應該當機立斷,要麼忍氣吞聲地繼續痛苦下去,要麼另謀出路。

慶幸的是,你不必在快樂和生産力之間做出選擇。實作快樂編碼的程式設計技術與那些最高效地生産出軟體的技術可以兼得。面向對象設計方法很好地解決了與程式設計相關的道德和技術兩大難題。遵循這些方法能生産出低成本的軟體,同時它所用的代碼也一樣讓人樂于處理。

1.1.1 設計解決的問題

假設要編寫一款新的應用程式。假設這款應用程式具備了一套完整、正确的需求。如果願意,你也可以另外假設一件事情:一旦編寫好了,這個應用程式絕不會再發生變化。

對于這種情況,設計就沒那麼重要了。像馬戲團的表演者在一個沒有摩擦力和重力的世界裡旋轉盤子一樣,你可以将這個應用程式編成動畫,然後自豪地退出來,并看着它一直不停地運轉下去。無論多麼不穩定,代碼盤都會不斷地旋轉,雖然會有些搖晃,但絕不會掉下來。

隻要什麼都不改變,一切都會安好。

很不幸,事情總是會發生變化。這是永恒不變的。客戶并不知道他們自己想要的是什麼,他們沒有說清自己的意圖。你并不了解他們的需求,你已學會了如何把事情做得更好。即使那些在各方面都很完美的應用程式,也是不穩定的。該應用程式取得了巨大的成功,現在每個人都還想要得到更多。變化不可避免:它無處不在,無所不在,無法逃避。

變化的需求就是程式設計中的摩擦力和重力。它們會引入各種力,而這些力都會作用到周密的計劃上,進而形成突發的和出人意料的壓力。正是這種對變化的需求讓設計變得如此重要。

易于更改的應用程式讓人樂于去編寫,也樂于去擴充。它們具有靈活性和适應性。那些抗拒變化的應用程式則正好相反:每一次的更改所付出的代價都很昂貴,每一次的更改都會讓下一次的更改成本變得更高。幾乎都沒人願意處理難以更改的應用程式。最嚴重的情況則會逐漸地變成了一部個人的恐怖電影:在裡面你扮演的是一名倒黴的程式員,瘋狂地從一個“轉盤”跑到下一個,竭力想要逃離陶瓷摔碎的聲音。

1.1.2 為何難以更改

面向對象的應用程式是由互動産生整體行為的各個零件組成。這些零件就是對象,而互動則展現在它們之間傳遞的那些消息裡。想要獲得發給正确目标對象的正确消息,需要這條消息的發送者對接收者有所了解。這一點會在這兩者之間建立許多依賴關系,并且這些依賴關系還是處在不斷變化之中。

面向對象設計與依賴關系管理(managing dependencies)相關。它是一套對依賴關系進行編排,以便各個對象能夠容忍更改的編碼技術。在缺乏設計的情形裡,非托管的依賴關系很容易造成嚴重破壞,因為這些對象之間彼此了解太多。更改其中的任何一個對象便會強制要求其合作者也随之發生變化;與之相反,當其合作者發生變化時也一樣會出現同樣的情況……如此下去,永無止境。一個看似無關緊要的增強,會導緻以同心圓交錯方式向外輻射的破壞,最終無法更改任何代碼。

當對象了解太多内容,它們對自己所在的世界便會有更多的期望。它們會變得很挑剔,它們會要求事情應該是“這個樣子”。這些期望會對它們産生束縛。在不同的環境裡,重用這些對象時,它們便會産生抗拒。它們測試起來是件痛苦的事,也難以被複制。

在一款小型應用程式裡,糟糕的設計并無大礙。即使每一個對象與其他所有對象都連接配接在一起,隻要在你的頭腦裡能夠一次性全部掌控它們,那麼你仍然可以改進這款應用程式。設計不當的小型應用程式所存在的問題是:如果它們成功了,那麼它們将成長為設計不當的大型應用程式。它們會逐漸成為泥塘,那時你便不敢再涉足它;否則會沉得無影無蹤。原本應該很簡單的更改可能會引起應用程式的連鎖反應,四處破壞代碼,以及要求大量的重寫。在這場交火中,測試也會被用上,然後它開始讓人覺得更像是一種障礙,而非一種幫助。

1.1.3 實用的設計定義

每款應用程式都由代碼集合而成,對代碼的編排就是設計。對于兩個獨立的程式員,即使他們有着共同的設計構思,在解決同一問題時,也可能會采用不同的方式來編排代碼。在流水線上同樣訓練有素的勞工可以制造出相同的零件,但設計不是流水線。設計更像是一個工作室,在那裡,志同道合的藝術家們雕刻出各具特色的應用程式。設計是一門藝術—一門編排代碼的藝術。

設計之是以困難,部分原因在于每一個問題都涉及兩個層面:你不僅要按今天的計劃編寫在将來要傳遞的代碼,而且還必須要建構出能顧及到以後會發生變化的代碼。在任何時間對過去所傳遞的測試版進行擴充,更改的成本最終都會侵蝕掉這個應用程式的最初成本。因為設計原則之間是交叉的,而且每一個問題都會涉及一個移動的時間表,是以設計挑戰會有一大堆令人眼花缭亂的可行解決方案。你的工作具有很高的綜合性:必須将對應用程式需求的總體了解,與各種設計選擇的利與弊的知識組合在一起;然後設計出在目前算是低成本,而在将來也能繼續保持那個樣子的代碼編排。

将未來情況考慮在内,似乎需要未蔔先知的能力,這通常會被認為超出了程式設計領域。實際并非如此!設計所考慮的未來并不是指你可以預測未知的需求,并在目前從中選擇一個來實作。程式員不是神仙。讓設計預測未來的特定需求,幾乎都不會有好的結果。實用的設計不會去預測未來将要發生什麼,它隻是接受什麼事情會發生,并且也接受你現在所不知道的事情。不要對未來進行猜測,你對未來隻保留有選擇接受的權利。如果不做選擇,則可以為以後的變化留出更大的餘地。

設計的目的是允許你以後可以進行設計,而設計的首要目标是降低變化所帶來的成本。

本文僅用于學習和交流目的,不代表異步社群觀點。非商業轉載請注明作譯者、出處,并保留本文的原始連結。

繼續閱讀