當我們打算跨越多種平臺開發程式時,「可攜性」講的並不是所有的程式碼,皆原封不動可在多個平臺編譯並執行。事實上,這幾乎是不可能的,針對每個平臺所獨有的特性,程式人終究還是必須撰寫特定的程式碼,才能夠在特定的平臺上執行。
盡量降低和特定平臺相依的程式碼數量,才能輕鬆跨平臺
雖然程式人終究得為不同的平臺撰寫特定的程式碼,但是,程式碼可攜性的實務意義,在於維持核心程式碼跨越多平臺的能力、盡量降低程式碼和特定平臺相依的數量,同時選擇究竟要執行在那一個平臺之上。
我們當然要降低和特定平臺相依的程式碼數量。當程式碼中處處和某個特定平臺相依時,這意謂著,想要切換到另一個平臺上時,這些程式碼都無法再使用。但倘若程式碼中僅有少數和平臺相依,那麼想要切換到另一個平臺時,只需要更換掉小部分程式即可。
由此可知,想要輕易地跨越多個平臺,不僅與平臺相依的程式碼要盡可能減少,而且,還必須盡可能簡化,從所支援平臺中擇一方式使用。
界定出各平臺的共通性,同時就會找出差異之處
「想要攜帶的範圍」決定了程式人要支援的平臺有哪些。當你想支援的平臺,彼此之間的共通性大時,表示程式人需要撰寫和特定平臺相依的程式碼就比較少。而想支援的平臺共通性少、差異性大時,自然意謂著程式人所需撰寫和特定平臺相依的程式碼數量就多了。
「界定目標平臺間的共通性以及差異」是可攜性設計時的重要活動。因為,當你能成功捕捉目標平臺之間的共通性時,便可以將它們抽離出來,成為所謂的核心程式碼。
這一類的程式碼具有很大的好處,因為它們代表各個目標平臺之間都一致的東西,也就是在每個平臺上都一樣,所以針對它們而寫的程式碼,每個平臺都能適用。能夠界定各平臺間的共通性,也就形同找出了各平臺間的差異,而差異就是必須針對各平臺重新寫過的部分。
可透過低階與高階相接的介面畫分程式碼
共通的程式碼有兩種,一種是本來就在各個平臺間沒有差別的程式碼。例如,對於音效處理的程式而言,混音的計算、等化器的計算等,是無論在那一個平臺上都應該相同的。
另一種共通的程式碼是,在高階的觀念上共通,但在低階的實作方式上有所差別。以圖像的處理程式為例,不同平臺要在畫面特定的座標上繪製指定寬、高的點矩陣圖(Bitmap),方式各有不同,但是,倘若已經有了繪製點矩陣圖的能力,要做出點矩陣圖在畫面上移動的效果就容易了,因為只需要不斷地改變同一張點矩陣圖繪製的座標就成了。
在這個例子裡,繪製點矩陣圖是低階的實作方式,而在這個基礎上,讓點矩陣圖在畫面上移動的方法,就是高階的觀念。
無疑地,低階的實作是和平臺相依的程式碼,但是,高階的觀念立足於低階的實作方式之上,卻完全和平臺無關了。
倘若我們沒有找出這裡所存在的共通性,那麼,不僅繪製點矩陣圖必須以和平臺相依的程式碼寫成,就連移動點矩陣圖的程式碼,都有可能以平臺相依的形式存在,那麼對於想要降低平臺相依之程式碼數量的目標,就有所違背了。
從這個例子你可以觀察到,其實我們是嘗試著分析出系統中高階及低階的部分。低階的部分涉及平臺的特殊性,高階的部分本身雖然操作低階部分,但不碰觸到任何的低階細節。我們可以說,透過低階與高階相接的介面,將與平臺相關的程式碼及無關的程式碼畫分開來。
決定介面的寬窄是程式人最重要的設計活動
說穿了,這還是回到我們常說的一個設計的大原則「針對介面來撰寫程式,而不要針對實作(Program to interface, not an implementation)」。和平臺相依的程式碼就是實作,我們可以透過築起一道介面,將它們隔離。
決定這個介面的長相,是程式人設計活動中最重要的一環。這個介面當然是越小越好,因為它深深影響著平臺相依程式碼的數量。對於跨平臺的可攜性設計而言,這個介面必須考量到所有的目標平臺,所以它必須是所有平臺的最大公約數。
我們可以從SDL(Simple DirectMedia Layer)中學到許多關於可攜性設計的技巧,尤其是關於介面的定義。舉例來說,在SDL中有一組函式是和執行緒有關的,SDL在SDL_thread.h中所定義的函式,即為SDL執行緒的高階介面。基於這個高階介面撰寫多執行緒程式,可以確保可以在SDL所支援的各種平臺上運行。
SDL_thread.h中所定義的函式,尚且不是用來切出與平臺相依程式碼的介面,SDL_thread.h中所定義的函式,其實是我們前段文字中所提到的高階的觀念,真正畫分出與平臺相依程式碼的介面,是在SDL_systhread.h中的函式。在這個介面之下,各作業系統各自實作此介面的函式。
舉例來說,對於產生執行緒,SDL_thread.h定義了一個叫做SDL_CreateThread()的函式,它是一個比較高階的函式,並且和平臺無關。在 SDL_systhread.h中,則定義了SDL_SYS_CreateThread()函式,它才是真正畫分出與平臺相依程式碼的介面,各個平臺例如Win32、pthread、OS/2、等等,各自會有一份SDL_SYS_CreateThread()的實作,而在SDL_CreateThread()中較為高階的程式碼,則會呼叫到SDL_SYS_CreateThread()(這是SDL_CreateThread()眾多的動作之一,但不完全只是單純地呼叫SDL_SYS_CreateThread()),最終也就對應到各個平臺上的真正的實作。
你可以觀察到,在SDL_systhread.h中所定義的函式僅有寥寥可數的三條相較於Win32或pthread所提供的API,可以說是簡化多了,這是因為倘若想要支援更多的平臺,就必須拋棄某些平臺的特性。
設計是根據應用的目的決定
決定這介面的內容,是對設計者的一大考驗。對於設計者來說,若能在這介面中加入越多的特性,便能夠發揮更多的威力,但是越多的特性,通常意謂著倚靠越多的原生支援,也就限制了能夠一體適用的平臺類型。
想要支援的平臺越多、越廣泛,越是得限縮這個介面的範圍,讓這個介面越抽象。所以,設計者必須取捨。
這也是本文中提到,當你想撰寫能跨越多個平臺的可攜性程式時,必須先設定「想要攜帶的範圍」的原因。
「想要攜帶的範圍」越廣,設計的介面就會越窄,相反的,「想要攜帶的範圍」較窄,所設計出來的介面就會較廣。
我們的設計是基於目的而做決策的。
作者簡介─王建興 |
|
清華大學資訊工程系的博士研究生,研究興趣包括電腦網路、點對點網路、分散式網路管理、以及行動式代理人,專長則是Internet應用系統的開發。曾參與過的開發專案性質十分廣泛而且不同,從ERP、PC Game到P2P網路電話都在他的涉獵範圍之內。 |
熱門新聞
2025-01-20
2025-01-20
2025-01-20
2025-01-24
2025-01-23