靜態方法和例項方法的區別以及如何恰當使用

huansky 發表於 2021-10-20

最近看到同事把一個私有例項方法改成了靜態方法,隱約記得有人曾經跟我說過儘量少用靜態方法,於是就和同事討論了下靜態方法和例項方法有啥區別,到底怎麼用比較合適。

於是在網上搜尋資料,但是很多都是粗略講了下,或者是複製貼上的。功夫不負苦心人,終於找到一篇文章說了靜態方法和例項方法的文章,並且作者還給出了原文連結:ABAP Static vs Instance method – Which to use when? 

下文直接搬運了 孟雨泊 的知乎文章 靜態方法和例項方法的區別以及何時使用

我們都在爭論何時使用靜態方法或例項方法。 在大多數情況下,我們會採用最簡單的方法,但這可能不是正確的方法。 讓我們嘗試探索並確定在確定“靜態”或“例項”時最好的方法是什麼。

在跳入差異和應該使用之前,請先檢查一下靜態方法和例項方法的基礎。

靜態方法

靜態方法是可以與類例項無關地呼叫的方法。 您只能在Static方法中訪問靜態屬性和靜態事件。

例項方法

例項方法是隻能使用物件引用呼叫的方法。 例項方法可以訪問例項屬性和例項事件。 

為什麼不使用靜態方法

從示例程式碼中可以看到,建立靜態方法聽起來不錯,而且很有利可圖,因為在呼叫方法時不涉及冗長的步驟-宣告引用變數,例項化物件和呼叫方法。 無需執行這些步驟即可直接呼叫靜態方法。 但是使用靜態的設計不會像聽起來那樣好。 讓我告訴你為什麼:

靜態方法無法重新定義

物件導向程式設計的最重要方面之一是多型性–只要需要,就用更具體的實現替換預設實現。在OO ABAP中,多型性將使用方法重新定義來實現。正如我們在前面的文章“覆蓋靜態方法”中所討論的,我們無法重新定義靜態方法。造成這種情況的主要原因是靜態方法可以獨立執行。使用靜態方法,可以通過顯式指定定義它們的型別來呼叫它們。這意味著,您可以直接呼叫實現,而該實現不繫結到例項物件的任何特定實現。

讓我們通過一個簡單的場景來了解這一點–如果您有使用BAPI進行銷售訂單建立的靜態方法。在設計時,此方法僅用於一種業務場景。現在,您想將此用於不同的業務場景。在這種新方案中,您需要在專案上設定一些其他欄位,例如“更高階別”專案,確定新專案類別等。您認為簡單的解決方案是在方法中新增一個程式碼塊來執行此邏輯XYZ銷售區域,ZABC訂單型別。您在這裡所做的事情是開啟一個框,您將在其中繼續新增越來越多的條件。因此違反了單一責任原則。

如果您具有Instance方法,則可以輕鬆繼承另一個類,重新定義該方法並替換現有的實現。在這個新的實現中,您將設定其他欄位並呼叫Super Method來完成其餘的工作。

單元測試

測試夾具

在ABAP單位中,可以使用稱為測試夾具的特殊方法設定測試資料。使用此方法後,將在您有權訪問測試資料的地方呼叫您的測試方法。由於每個ABAP單元測試都應該可以單獨進行操作和測試,因此靜態方法很難進行測試。靜態方法將使用靜態屬性,並且由於它們正在使用靜態屬性,因此您必須在測試夾具方法中始終具有其他邏輯來擺脫它們。

如果您正在使用例項的物件,則可以輕鬆清除它。當例項化一個新物件時,舊物件將被取消引用而無需任何其他邏輯

建構函式

與例項方法的CONSTRUCTOR方法相反,使用靜態方法的設計最終將使用CLASS_CONSTRUCTOR。 如前所述,CLASS_CONSTRUCTOR and CONSTRUCTOR: Who comes before whom?,很難預測何時呼叫CLASS_CONSTRUCTOR。 首次訪問該類時可以呼叫CLASS_CONSTRUCTOR,即使已訪問該類以獲得常量值也是如此。 這使其無法操作且無法測試。

在同一會話中重用該實用程式

靜態屬性將繫結到記憶體,直到會話結束。這意味著,如果僅設定一次值,則在會話結束之前不會清除它們。如果是靜態屬性,則不可能在同一會話中利用相同的邏輯。例如。一個簡單的實用程式類,用於生成應用程式日誌。

舉個例子:

  • 在靜態類的屬性中收集日誌
  • 收集後呼叫靜態方法以生成應用程式日誌。

該設計似乎完全適合應為靜態的實用程式類。但這是一個問題,它限制了您在同一會話中再次使用相同的邏輯而不會丟失現有資訊。可以說,您正在使用此應用程式日誌收集錯誤。現在,在同一程式中,您將不會生成另一個應用程式日誌來跟蹤執行的活動。由於您已收集了靜態屬性中的所有錯誤,因此除非將其複製到另一個佔位符並呼叫Utility類以生成跟蹤日誌,否則當您嘗試使用同一Utility類時,您將丟失錯誤日誌資料。

另一方面,您使用例項方法和屬性進行了設計,則可以簡單地建立另一個例項並開始使用它來跟蹤日誌。

總結

因此,基於所有這些事實,我們可以得出以下經驗法則:

  • 如果打算建立靜態方法將使用的任何靜態屬性,請考慮建立例項方法。它將允許您使用多個例項。它還允許您控制何時可以釋放繫結的記憶體。

  • 如果您認為將來有機會新增條件邏輯,請使用例項方法。通過利用Redefinition,利用多型來使設計更加靈活

  • 靜態僅應用於物件建立的設計模式,例如Singleton,Factory Method,Abstract Factory,Singleton Factory,以方便物件建立。

  • 靜態應該用於純實用程式類,而不用於助手類。

 

文章看完後,我簡單說下我的理解:

  • 靜態方法之所以不推薦使用是因為其缺乏擴充套件性,一旦使用靜態方法,物件導向的繼承多型特性也就不再適用。後續在往靜態方法中新增邏輯就會出現很多 if else,因為你無法保證不同業務方的要求是一樣的。比較好的做法是建立一個介面或者抽象類,讓不同業務場景自己去實現,這樣即使變化也不會相互影響。

  • 如果一定要使用靜態方法,一定要確保該方法以後不會再出現修改和迭代。靜態方法適用場景:工具方法比如 Math.max(),檔案讀寫,單例,工廠模式等;

  • 如果是併發場景,也不推薦使用靜態方法,你無法保證執行緒安全,有可能存在多個執行緒同時呼叫,此時你無法確定得到的結果是否是對的。如果給靜態方法新增鎖就得不償失了,此時,例項方法是一個好的選擇。