面向新手的雜談:Flyweight

今天上課時突然被學生問起了Flyweight的問題,又由此稍微聯想到了一點更多的東西,因此想稍微寫一點

按照非常教科書的說法,Flyweight模式就是讓擁有某些相同特質的實例共享這些相同點,從而降低內存開銷以提升效率。

那麼什麼時候會用到Flyweight呢?最常見的場景之一想必就是在遊戲開發時復用的資源了吧。一個圖片/音頻數據被不同的Sprite Instance以不同的方式使用,從而構建出看起來頗為複雜的場景是各種遊戲開發者最為擅長做法了,而不同的Instance中只需要包括各自必須的獨立數據即可。

那麼除此之外,還有哪些場景是我們可以用到Flyweight模式的呢?

很多人也許會舉例諸如文件啦字體啦資料庫啦之類等等的場景,這些都沒有問題,但是我更希望傳達的是另一個可能不是很受關注的場景:代碼本身的復用。

設計模式作為一種抽象模型,並沒有任何規定說其必須應用於某些層面,因為從代碼層面來講,每一段代碼本身亦即可看成某一個實例。對於一些編程經驗不足的學生和新人而言,時常出現的重複代碼是一個不會影響程序表現,卻會影響程序可維護性的,必須特別注意的情況。

什麼時候需要關注代碼復用呢?

在軟體的開發階段,任何時候當發現兩段代碼有非常相似的結構時,就需要考慮代碼復用的問題了。這一點在使用C#/Java進行Event Driven Dev的時候尤為明顯,不同的EventHandler觸發後指向某一類行為相同的邏輯過程,那麼這些過程就可以看作某種具有「可共享」性質的代碼單元實例,從而將其抽取出來作為獨立的方法(函數)存在,並設計參數列表以供調用。

代碼復用所帶來的好處並不僅僅在於大幅度的縮減代碼尺寸,同時還可以避免某一個特定邏輯需要修改兩處以上的地方所帶來的潛在的維護失誤的風險,可以說,能否有效的整理代碼進行復用,是一個開發者從入門走向專精的必經之路。

然而凡是皆需有度,過度的抽取代碼避免復用在某些時候也會造成一些問題,例如過於臃腫的層級等等。就個人建議而言,可以用兩個簡單的標準來衡量一段代碼值得抽取出來用於復用:

1. 這段代碼如果被抽取,那麼傳入的參數里是否需要包含回調函數?

2. 這段代碼如果被抽取,那麼執行後返回值是否只用簡單變數(int, bool, enum等),且不包含其他必須以傳址方式來給出計算結果的參數?

對於任何一段抽取後的代碼,如果以上兩個條件都為真,那麼我會認為這個代碼是值得進行抽取封裝的。反之,則需要認真考量代碼本身是否在不同的場景下有較大的行為差別,從而判斷其是否適合復用。

推薦閱讀:

TAG:編程 | 設計模式 |