[譯]Kotlin中是應該定義函數仍是定義屬性?

翻譯說明:java

原標題: Kotlin: should I define Function or Property?緩存

原文地址: blog.kotlin-academy.com/kotlin-shou…session

原文做者: Igor Wojda數據結構

最近,我對屬性和函數用法方面感到困惑。這是一個很好的機會去介紹有關Kotlin屬性的概念。那麼問題來了,何時使用函數或者使用屬性呢?我建議你遵循如下最簡單的規則:ide

  • 屬性是描述狀態
  • 函數是描述行爲

讓咱們進一步探討他們。屬性表明着一個能夠描述對象狀態的數據結構,例如: Person對象能夠有name、lastNameweight屬性。函數

class Person (var name:String, var lastName:String, var weight:Double)
複製代碼

咱們還能夠建立一個派生屬性,用於返回fullName,它是由namelastName兩個屬性組合而成的。post

class Person (var name:String, var lastName:String, var weight:Double) {
    val fullName = "$name $lastName"
}
複製代碼

在上述例子中,在Person對象建立期間,屬性值fullName僅僅被賦值一次。有時這是一個理想的行爲,可是在這個例子中,當咱們去改變了name或者lastName的屬性值時,被存儲在fullName的值不會被更新。幸運的是,Kotlin也提供了使用getter或者setter去自定義屬性訪問器的能力。在下面例子中fullName屬性的值會在每一次被訪問的時候都會被賦值。學習

class Person (var name:String, var lastName:String, var weight:Double) {
    val fullName
        get() = "$name $lastName"
}
複製代碼

函數,在另外一方面包含了對象全部能夠被執行的行爲或者動做。咱們的Person類能夠有 run(),walk()jump() 的方法。ui

class Person () {
    fun run() { /*doSth*/ }

    fun walk() { /*doSth*/ }

    fun jump() { /*doSth*/ }
}
複製代碼

重要的是須要注意,該方法可能會有一個間接修改對象狀態的反作用,例如咱們每調用一次 jump() 方法都會使得person對象中的weight屬性值減小0.1this

class Person (var name:String, var lastName:String, var weight:Double) {
    //..

    fun jump() { 
        weight -= 0.1   
        /*doSth*/ 
    }
}
複製代碼

若是你仍然困惑於何時使用屬性或函數,那麼接下來將會從外部調用者的角度去回答這個問題。咱們先暫時無論其內部的實現(一個屬性被存儲在哪裏或者行爲怎麼實現的)而且須要更加簡單地去看待外部的API(相似於加入第三方的庫到項目中,咱們僅僅關注其庫提供API便可)

person.name = "Igor"
person.weight = 79
person.jump()
person.jump()
person.jump()
複製代碼

使用Kotlin屬性好處之一在於屬性訪問器更加簡潔的語法(咱們可使用height 去替代getHeight()/setHeight()方法),此外就是getter和setter方法更加接近於屬性的聲明,不像Java,咱們一般會在一個類的頂部定義成員屬性,而後在其下面定義getter和setter方法。我喜歡屬性委託這個特性,它能夠提升複用代碼的能力。咱們能夠初始化一個變量僅僅當它被須要使用的時候(lazy delegate) ,不管何時屬性的值發生變化,能夠執行一些動做(Observable delegate)或者使用自定義委託實如今另外一對象(Android shared preferences, map, browser session, database…) )中簡單地存儲咱們屬性.

不錯的是Kotlin容許咱們在接口中均可以使用函數和屬性

//BAD
class Person () {
    private var weight:Double = 0

    fun setWeight(weight:Double) {
        this.weight = weight
    }

    fun getWeight(): Double {
        return weight
    }
}

//GOOD
class Person (var weight:Double)
複製代碼

當咱們看到一個以set爲前綴(如: setHeight())開頭的方法、只有一個參數而且被指定爲private的變量或者以get爲前綴(如: getHeight())開頭的方法、返回一個被指定爲private的變量時,咱們應該定義一個屬性來替代它。

指南: 如何作這個決定?

每次你想去聲明一個新的函數時,你須要問本身兩個問題:

  • "它是描述一個行爲嗎?"-- 將描述行爲的函數做爲候選者,例如 run(),walk()和jump()
  • "它是描述一個狀態嗎?"-- 將描述狀態的函數做爲候選者,例如name,lastName和weight

這裏還有一系列額外來自Effective Java(若是沒記錯的話)的幫助指南讓咱們瞭解定義屬性優於函數。

  • 不會拋出異常
  • 以簡單廉價方式去計算(或者在第一次運行時被緩存)
  • 在多個調用中返回相同的結果

以上的指南應該能夠給你一個不錯的建議,何時去使用函數或者屬性。在一開始,定義屬性或許有點不適應(特別是Java開發者),可是相信我--一段時間後,這個決定是明智的。

譯者有話說:

  • 一、我爲何要翻譯Kotlin系列博客?

咱們都知道Kotlin這門語言流行不久,目前在國內沒有被大面積應用於實際項目中,而在國外這門語言則很是流行,有不少公司也在大量運用它,在今年的Google IO上,Google官方說他們有35%的工程師喜歡使用Kotlin,因此國外一些Kotlin相關的博客質量都還不錯。也包括了他們使用Kotlin在一些實際項目中的經驗。一門語言必定得在實際應用中體現它的價值,因此有必要去學習學習。因爲國外博客都是英文的,因此我作了一些翻譯的事情以及我對這邊博客感覺並提煉一些重要點出來。歡迎繼續關注~

  • 二、我爲何要翻譯這篇博客?

咱們知道學習Kotlin的語法時候與應用於開發是有差距的,在使用過程當中會遇到各類選擇的問題,好比這篇博客是闡述在Kotlin中咱們何時去定義一個屬性,何時去定義一個函數呢?這個問題是從基本語法學習中得不到的,得從實際需求和使用經驗中去體會,對於Java轉Kotlin的初學者而言,很容易受到Java語言思想去任意定義函數。由於在Java中是沒有自定義屬性訪問器一說,改變狀態惟有經過函數唄。而在Kotlin提供了一個更爲簡單方式去改變屬性狀態。因此當你還在用Java語言思想在使用Kotlin的語言,不妨真正去思考一下使用Kotlin來寫優點在哪裏?

  • 三、這篇博客核心點提煉?

關於何時用函數何時用屬性: 描述狀態時,用屬性;描述行爲時,用函數

看個例子再次體會下(關於自定義屬性訪問器的知識能夠查閱我以前的淺談系列博客中變量和常量那篇):

Java部分代碼例子實現

//對於Java而言沒有Kotlin中屬性訪問器之說,對於須要每次訪問時都
//必須保證拿到最新狀態時,Java中惟一好的處理方式就是定義函數,例如isIdling()、isEnded()方法
class VideoPlayer{
    public boolean isIdling() {//描述的是狀態
        return this.mPlayer != null && this.mPlayer.getPlaybackState() == 1;
    }

    public boolean isEnded() {//描述的是狀態
        return this.mPlayer != null && this.mPlayer.getPlaybackState() == 4;
    }
    
    public void play(){//描述的是行爲動做
        //do sth 
    }
    
    public void resume(){//描述的是行爲動做
        //do sth
    }
}

//調用
if (mVideoPlayer.isEnded() || mVideoPlayer.isIdling()) {
    mVideoPlayer.play();         
}else{
    mVideoPlayer.resume();
}
複製代碼

Kotlin代碼例子實現

class VideoPlayer{
   var mIsIdling = false//描述的是狀態
       get() = this.mPlayer != null && this.mPlayer.getPlaybackState() == 1
   var mIsEnded = false//描述的是狀態
       get() = this.mPlayer != null && this.mPlayer.getPlaybackState() == 4
    
    fun play(){//描述的是行爲動做
        //do sth 
    }
    
    fun resume(){//描述的是行爲動做
        //do sth
    }
}

//調用
if (mVideoPlayer.mIsEnded || mVideoPlayer.mIsIdling) {
    mVideoPlayer.play()         
}else{
    mVideoPlayer.resume()
}
複製代碼

歡迎關注Kotlin開發者聯盟,這裏有最新Kotlin技術文章,每週會不按期翻譯一篇Kotlin國外技術文章。若是你也喜歡Kotlin,歡迎加入咱們~~~

相關文章
相關標籤/搜索