2013年4月7日 星期日

亂談 Adapter Pattern

這個學期我選修了音樂訊號分析與檢索,這門課大量使用了 Matlab 來做音訊的處理,要做一些錄音的動作。我們會使用課程提供或者自己寫的 Matlab script 來進行錄音、讀取音訊或處理,在課程提供的程式之中很大量的使用到了 Matlab 的 wav* 系列函式,對我而言不幸的是,裡面大量的使用了 wavrecordwavplay 這兩個函式。這也是今天可以來亂談一下 Adapter Pattern 的原因。

據我所知, Matlab 是疊在 Java 之上的,基本上跨平台,不過沒想到 wavrecord wavplay 之類的函式竟然是平台綁定,在課程的投影片上甚至還有提到不支持64位元的Windows,頗為神妙。有些時候,我很不能忍受一些 Windows Only 的東西,想不到在跨平台的東西上面還會看到平台綁定的函式。本來這篇是打算來戰資訊系課程是否應該使用 Windows Only 的理由,不過寫了三大段之後發現偏離主題就先通通拿掉了以後再來談談

如果在非 Windows 的機器上執行 wavrecordwavplay ,會看到「WAV* is only for use with Windows machines.」的回應,在最近幾次的作業中需要使用課程提供的錄音腳本來進行大量的錄音工作(唸 0~9,a~z 或唱 20 首歌之類的),必須依照該腳本程式生成的格式繳交。

我的 Windows 都是虛擬機,我並不想要為了完成這份作業就在虛擬機裡面灌 Matlab,我也不想要用蔽校計中提供的 IE Only AppShare 的功能,我有一台實體的 Linux 和 Mac ,上面都已經有 Matlab ,我希望可以利用 Linux / Mac 來完成我的作業。

我必須使用課程提供的程式,但是卻又希望我可以在非 Windows 的環境執行這份程式,為此我想到的解決方法就是自己寫一份 wavrecordwavplay ,直接覆蓋掉在 Linux / Mac 上的那一份不能執行的函式。

我把程式碼都放在這裡了,有需要的朋友請自行 clone 或 fork 吧 :p

Object Adapter Pattern UML,圖片來源:Wikipedia

後來我想想這樣的處理方法或許稱得上是 Adapter Pattern 的應用。小時候學 Design Patterns 在教 Adapter Pattern 的時候,是說目的是為了

將介面轉換成外界所預期的另一種介面,讓原先因為介面不相容而無法協力合作的類別能夠兜在一起。

在這個例子裡,沒有寫成物件,只是函式的轉發,所以說應該是 Function Adapter (?)。外界(Client),也就是課程提供的程式,其所預期的介面 adaptor.methodA() 是 wavrecord() 或是 wavplay() ,因此我寫了
function wavplay(y,Fs,mode)
%略 
ap = audioplayer(y,Fs);
%略
if strcmp(mode,'sync')
    %略
    playblocking(ap);
else
    %略
    play(ap);
end
%略
function y = wavrecord(n,Fs,ch,dtype)
%略
recorder = audiorecorder(Fs,nbits,ch);
recordblocking(recorder,n/Fs);
y = getaudiodata(recorder,dtype);
%略
這兩個 Adapter ,呼叫跨平台的新 API audiorecorderaudioplayer 這兩個 Adaptee 來完成在 Windows 下的老 API wavrecordwavplay 的工作。

最後我在 matlabrc.m 內將這兩個 Adapter 的路徑加進去,蓋掉原生的函式,就能順利用 Linux / Mac 完成作業了 :)