<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          kotlin修煉指南6-Sealed到底密封了啥

          共 5312字,需瀏覽 11分鐘

           ·

          2021-09-14 18:59

          點(diǎn)擊上方藍(lán)字關(guān)注我,知識(shí)會(huì)給你力量


          在代碼中,我們經(jīng)常需要限定一些有限集合的狀態(tài)值,例如:

          • 網(wǎng)絡(luò)請(qǐng)求:成功——失敗
          • 賬戶狀態(tài):VIP——窮逼VIP——普通
          • 工具欄:展開——半折疊——收縮

          等等。

          通常情況下,我們會(huì)使用enum class來做封裝,將可見的狀態(tài)值通過枚舉來使用。

          enum class NetworkState(val value: Int) {
              SUCCESS(0),
              ERROR(1)
          }

          但枚舉的缺點(diǎn)也很明顯,首先,枚舉比普通代碼更占內(nèi)存,同時(shí),每個(gè)枚舉只能定義一個(gè)實(shí)例,不能拓展更多信息。

          除此之外,還有種方式,通過抽象類來對(duì)狀態(tài)進(jìn)行封裝,但這種方式的缺點(diǎn)也很明顯,它打破了枚舉的限制性,所以,Kotlin給出了新的解決方案——Sealed Class(密封類)。

          創(chuàng)建狀態(tài)集

          下面我們以網(wǎng)絡(luò)請(qǐng)求的例子來看下具體如何使用Sealed Class來進(jìn)行狀態(tài)的封裝。

          和抽象類類似,Sealed Class可用于表示層級(jí)關(guān)系。它的子類可以是任意的類:data class、普通Kotlin對(duì)象、普通的類,甚至也可以是另一個(gè)密封類,所以,我們定義一個(gè)Result Sealed Class:

          sealed class Result<out T : Any> {
              data class Success<out T : Any>(val data: T) : Result<T>()
              data class Error(val exception: Exception) : Result<Nothing>()
          }

          當(dāng)然,也不一定非要寫在頂層類中:

          sealed class Result<out T : Any> 
          data class Success<out T : Any>(val data: T) : Result<T>()
          data class Error(val exception: Exception) : Result<Nothing>()

          這樣也是可以的,它們的區(qū)別在于引用的時(shí)候,是否包含頂層類來引用而已。

          大部分場(chǎng)景下,還是建議第一種方式,可以比較清晰的展示調(diào)用的層級(jí)關(guān)系。

          在這個(gè)例子中,我們定義了兩個(gè)場(chǎng)景,分別是Success和Error,它表示我們假設(shè)的網(wǎng)絡(luò)狀態(tài)就這兩種,分別在每種狀態(tài)下,例如Success,都可以傳入自定義的數(shù)據(jù)類型,因?yàn)樗旧砭褪且粋€(gè)class,所以借助這一點(diǎn),就可以自定義狀態(tài)攜帶的場(chǎng)景值。在上面這個(gè)例子中,我們定義在Success中,傳遞data,而在Error時(shí),傳遞Exception信息。

          所以,使用Sealed Class的第一步,就是對(duì)場(chǎng)景進(jìn)行封裝,梳理具體的場(chǎng)景枚舉,并定義需要傳遞的數(shù)據(jù)類型。

          ?

          如果場(chǎng)景值不需要傳遞數(shù)據(jù),那么可以簡(jiǎn)單的使用:object xxxx,定義一個(gè)變量即可。

          ?

          使用

          接下來,我們來看下如何使用Sealed Class。

          fun main() {
              // 模擬封裝枚舉的產(chǎn)生
              val result = if (true) {
                  Result.Success("Success")
              } else {
                  Result.Error(Exception("error"))
              }

              when (result) {
                  is Result.Success -> print(result.data)
                  is Result.Error -> print(result.exception)
              }
          }

          大部分場(chǎng)景下,Sealed Class都會(huì)配合when一起使用,同時(shí),如果when的參數(shù)是Sealed Class,在IDE中可以快速補(bǔ)全所有分支,而且不會(huì)需要你單獨(dú)補(bǔ)充else 分支,因?yàn)镾ealed Class已經(jīng)是完備的了。

          所以when和Sealed Class真是天作之合。

          進(jìn)一步簡(jiǎn)化

          其實(shí)我們還可以進(jìn)一步簡(jiǎn)化代碼的調(diào)用,因?yàn)槲覀兠看问褂肧ealed Class的時(shí)候,都需要when一下,有些時(shí)候,也會(huì)產(chǎn)生一些代碼冗余,所以,借助拓展函數(shù),我們進(jìn)一步對(duì)代碼進(jìn)行簡(jiǎn)化。

          inline fun Result<Any>.doSuccess(success: (Any) -> Unit) {
              if (this is Result.Success) {
                  success(data)
              }
          }

          inline fun Result<Any>.doError(error: (Exception?) -> Unit) {
              if (this is Result.Error) {
                  error(exception)
              }
          }

          這里我對(duì)Result進(jìn)行了拓展,增加了doSuccess和doError兩個(gè)拓展,同時(shí)接收兩個(gè)高階函數(shù)來接收處理行為,這樣我們?cè)谡{(diào)用的時(shí)候就更加簡(jiǎn)單了。

          result.doSuccess { }
          result.doError { }

          所以when和Sealed Class和拓展函數(shù),真是天作之合。

          那么你一定好奇了,Sealed Class又是怎么實(shí)現(xiàn)的,其實(shí)反編譯一下就一目了然了,實(shí)際上Sealed Class也是通過抽象類來實(shí)現(xiàn)的,編譯器生成了一個(gè)只能編譯器調(diào)用的構(gòu)造函數(shù),從而避免其它類進(jìn)行修改,實(shí)現(xiàn)了Sealed Class的有限性。

          封裝?

          Sealed Class與抽象類類似,可以對(duì)邏輯進(jìn)行拓展,我們來看下面這個(gè)例子。

          sealed class TTS {
              
              abstract fun speak()

              class BaiduTTS(val value: String) : TTS() {
                  override fun speak() = print(value)
              }

              class TencentTTS(val value: String) : TTS() {
                  override fun speak() = print(value)
              }
          }

          這時(shí)候如果要進(jìn)行拓展,就很方便了,代碼如下所示。

          class XunFeiTTS(val value: String) : TTS() {
              override fun speak() = print(value)
          }

          所以,Sealed Class可以說是在抽象類的基礎(chǔ)上,增加了對(duì)狀態(tài)有限性的控制,拓展與抽象,比枚舉更加靈活和方便了。

          再例如前面網(wǎng)絡(luò)的封裝:

          sealed class Result<out T : Any> {
              data class Success<out T : Any>(val data: T) : Result<T>()
              sealed class Error(val exception: Exception) : Result<Nothing>() {
                  class RecoverableError(exception: Exception) : Error(exception)
                  class NonRecoverableError(exception: Exception) : Error(exception)
              }

              object InProgress : Result<Nothing>()
          }

          通過Sealed Class可以很方便的對(duì)Error類型進(jìn)行拓展,同時(shí),增加新的狀態(tài)也非常簡(jiǎn)單,更重要的是,通過IDE的自動(dòng)補(bǔ)全功能,IDE可以自動(dòng)生成各個(gè)條件分支,避免人工編碼的遺漏。

          向大家推薦下我的網(wǎng)站 https://xuyisheng.top/  點(diǎn)擊原文一鍵直達(dá)

          專注 Android-Kotlin-Flutter 歡迎大家訪問



          往期推薦


          本文原創(chuàng)公眾號(hào):群英傳,授權(quán)轉(zhuǎn)載請(qǐng)聯(lián)系微信(Tomcat_xu),授權(quán)后,請(qǐng)?jiān)谠瓌?chuàng)發(fā)表24小時(shí)后轉(zhuǎn)載。
          < END >
          作者:徐宜生

          更文不易,點(diǎn)個(gè)“三連”支持一下??


          瀏覽 36
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  乱伦视频国产 | 日韩午夜毛片 | 五月天在线欧美日韩在线 | 影音先锋人人操 | 暴操美女视频网站 |