2016-11-14 134 views
4

所以如果擴展方法和擴展屬性真的是靜態方法和屬性。靜態方法和屬性和方法不是線程安全的,因此應該避免使用擴展方法和擴展屬性。擴展方法和擴展屬性是不好的做法嗎?

我們只是被欺騙來做這些事情,因爲我們編寫的代碼會顯示爲漂亮或乾淨,但在性能方面並非如此。

這是真的嗎?

+8

沒有,聲明「靜態方法不是線程安全的「是不正確的(並且它都是錯誤的)。 – Ilya

回答

7

這取決於你如何寫擴展功能/屬性。如果他們不編輯或訪問共享狀態,即屬性和功能是清晰的功能:這絕對不是壞習慣。

實施例1:

fun String.countSpaces(): Int { 
    return this.count { c -> c == ' ' } 
} 

該功能完全在多線程環境中,由於String是不可變的。

實施例2:

data class MutablePerson(val name: String, var speech: String) 

fun MutablePerson.count(nextNumber: Int) { 
    this.speech = "${this.speech} ${nextNumber}" 
} 

此功能變異MutablePerson對象的speech屬性和分配操作不原子。如果count將從不同線程的一個對象上調用 - 可能出現不一致的狀態。

例子:

fun main(args: Array<String>) { 
    val person = MutablePerson("Ruslan", "I'm starting count from 0 to 10:") 

    (1..10).forEach { it -> 
     Thread({ 
      person.count(it) 
      println(person.speech) 
     }).start() 
    } 

    Thread.sleep(1000) 

    println(person.speech) 
} 

可能的輸出:

I'm starting count from 0 to 10: 1 
I'm starting count from 0 to 10: 1 3 
I'm starting count from 0 to 10: 1 3 4 
I'm starting count from 0 to 10: 1 3 4 2 
I'm starting count from 0 to 10: 1 3 4 2 5 
I'm starting count from 0 to 10: 1 3 4 2 5 8 
I'm starting count from 0 to 10: 1 3 4 2 5 6 
I'm starting count from 0 to 10: 1 3 4 2 5 6 7 
I'm starting count from 0 to 10: 1 3 4 2 5 6 7 9 
I'm starting count from 0 to 10: 1 3 4 2 5 6 7 9 10 
I'm starting count from 0 to 10: 1 3 4 2 5 6 7 9 10 

所以擴展功能和擴展性也不錯的做法,他們就像在類的屬性和方法:這取決於你如何寫他們線程安全與否。

7

靜態方法與實例方法一樣擁有自己的堆棧。因此,靜態方法中的臨時變量就像實例方法一樣在棧上。交給靜態方法的參數在訪問共享狀態時可能會遇到線程問題,但這與實例方法的情況完全相同。

想象Java中帶有靜態方法的大量的Util類作爲Java沒有擴展函數的解決方法。在多線程方面沒有什麼問題。

在C#擴展方法

也在現場靜態方法後面,它不會做任何傷害,看到How extension methods are implemented internally

0

正如你所說,擴展函數,靜態解決。所以如果你開始使用擴展功能作爲創建實用程序類的方法,那麼這是一個不好的做法。

在Java中,Utils類通常是一種不好的做法,不僅是因爲線程安全,而且因爲它們可能是惡劣設計的代碼味道,因爲它們很難測試。

靜態方法的主要問題是它們不能被嘲笑(至少與Mockito一起),所以你會提出無法測試你的代碼。

但是,如果你使用的擴展功能,對於有沒有必要進行再測試,這根本不是一個不好的做法小型的,孤立的任務(如幫手敬酒,日誌...)