fbpx

亂談程式設計的小惡魔 - 靜態函式

程式設計的小惡魔,你的名字是 「靜態函式」

程式設計中幾乎都會用到 Function Call,我想這應該是結構化程式設計重要的元素之一。伴隨著物件導向程式設計的普及與氾濫,程式設計師對於 Function Call 不陌生,一天總要寫個幾百次才過癮。為什麼說"物件導向程式設計"氾濫呢?因為現在假設哪種語言沒有物件的概念,常常會覺得這個語言遜掉了....... -_-

其實 Function Call 不需要介紹也沒什麼特別的,特別的是它的寫法與實作千變萬化。今天我想談的是靜態函式/類別函式 (Static Method),為什麼需要謹慎思考靜態函式呢?因為我們常常覺得靜態函式非常好用與便利,久而久之就會移遺忘靜態函式對系統造成的影響,或者根本沒想過呼叫靜態函式對系統有何影響?好吧.......讓我們來看看靜態函式

Method 就是 Method,是不是靜態有差嗎?沒錯,除了靜態變數要注意多時序 (MultiThread) 的問題外,似乎絕大多數的靜態函式在使用上與實體化 (Instance) 的物件方法用起來效果差不多,甚至更方便且程式寫起來更短,這些優點真是太吸引我們了,我們應該鼓吹大量使用靜態函式才對....... -_- 我只是開開玩笑!!

但是靜態函式有一個缺點,就是靜態函式在同一個 Runtime (同一個Runtime可以想像為同一個程序) 中所使用的記憶體位置是相同的,也就是所謂的獨生子 (Singleton)。通常如此之目的是希望系統能確保 Class 在 Runtime 中只有一個唯一的實例 (Instance),常常用在兩個實例間的溝通。假設想讓寫出來的程式同時擁有可實例化與保留靜態的獨生性 (Singleton) 與互通性,最常見到的 Desgin Pattern 就是 getInstance(),如下所示(Java example):

public class Singleton { 

    private static Singleton self = null;

    public static Singleton getInstance() {
        if (self==null) {
            self = new Singleton();
        }
        return self;
    }

    public void run() { 
        //Running
    }

}

 有了上述的程式,我們就可以透過 Singleton.getInstance().run() 來調用函式,也可以 new Singleton() 後再調用實例化的函式,哇.......真方便,我相信這樣的寫法已經普遍出現在各種系統與 API 中。然而我以前撰寫的程式也常有這樣的影子出現,表面上似乎解決的問題,實際上只是把靜態函式變得能夠不靜態了

拉回正題,讓我們思考調用靜態函式對系統的影響吧。說穿了,就是依賴關係,當你直接使用類別中的靜態方法時,你的程式碼已經跟這個類別產生依賴關係。複雜的依賴關係對於系統的維護與彈性是有阻礙的。假設靜態函式修改了,那麼你就必須把所有調用靜態函式的程式碼重新 Review 一次,這樣可是很累的工作。

有了不少教訓以後,我慢慢的少寫靜態函式了,大部分盡可能設計出需要實體化的類別,未來可透過上層框架的管理來調用函式,大幅提高程式重用性。除了僅處理計算或轉換的功能才會寫成靜態函式(類別函式)之外,現在確實不太設計靜態函式了。

此外在許多著名的 IoC / DI 的實作框架中,更是不推崇靜態類別函式的呼叫,如此將會提降低系統的耦合度。假設不這麼做,久而久之將會造成系統的負擔與累積包袱,演變成必須砍掉重練的情況。然而在早期沒有完整軟體測試的系統中,系統重構的風險是很高的,系統重構又是另一門學問了,有機會再與大家分享。

物件導向優點多於缺點是絕對的,善用 Design Pattern 避免缺點寄居在我們所設計的系統中,那麼物件導向將會是很優異的程式設計風格。

  4 comments for “亂談程式設計的小惡魔 - 靜態函式

發佈留言