Kotlin使用心得(十二):Sealed Class

Carter Chen
5 min readOct 31, 2018

--

“envelope paper lot” by Joanna Kosinska on Unsplash

如果要在Java中列舉,我們可能會用Enum,而在Kotlin中,除了Enum以外,還有一個更加強大的工具——Sealed Class。

Enum Class

在Kotlin中的枚舉類可以寫成:

然後使用when來判斷:

枚舉類也可以自帶參數:

使用看看:

大guy~94醬。

Sealed Class:Enum Class 2.0

來看看Sealed Class有什麼特性吧!以下內文大部分從這篇文章翻譯過來:

首先,先創造一個名為Operationsealed class,加上execute()方法,來玩玩看:

sealed class是個很酷的class,以上面的代碼為例:·類別中有4個class,分別是AddSubtractMultiplyDivide,而且

也只能有這4個class。什麼意思呢?

讓我們用execute()方法來測試看看Operation類別所有的枚舉情況:

fun execute(x: Int, op: Operation) = when (op) {
is Operation.Add -> x + op.value
is Operation.Subtract -> x - op.value
is Operation.Multiply -> x * op.value
is Operation.Divide -> x / op.value
}

如果我們試圖將其中一種枚舉情況刪除:

fun execute(x: Int, op: Operation) = when (op) {
is Operation.Add -> x + op.value
is Operation.Subtract -> x - op.value
is Operation.Multiply -> x * op.value
// delete this line
}

Compiler就會有森77的fu:

‘when’ expression must be exhaustive, add necessary ‘is Divide’ branch or ‘else’ branch instead

翻譯:when表達是應該是要全面性的,應該要包含「其他」情況

所以我們加入else代表其他未過濾的枚舉情況,就可以解決這個警告:

fun execute(x: Int, op: Operation) = when (op) {
is Operation.Add -> x + op.value
is Operation.Subtract -> x - op.value
is Operation.Multiply -> x * op.value
else -> x
}

也就是說,你可以在Sealed Class中定義所有可能的情況,而在搭配when的使用下,compiler會強迫我們得去注意到這些情況是否都有被處理到,是個非常貼心的設計。

想像一下今天我們要開個API給別人,他可能不會知道一個參數status的所有種類,但透過Sealed Class與when的組合,可以強迫這個API的使用者去了解所有的種類,並進行處理。

基本上一個Sealed Class的Subclass預設不帶任何參數,它會是個object:

注意到了嗎?當搭配when做使用的時候,但參數的Sealed Class subclass需要使用is判斷,不帶參數的Object不需要使用is判斷:

fun execute(x: Int, op: Operation) = when (op) {
is Operation.Add -> x + op.value
is Operation.Subtract -> x - op.value
is Operation.Multiply -> x * op.value
is Operation.Divide -> x / op.value
Operation.Increment -> x + 1
Operation.Decrement -> x - 1
}

因為Kotlin中的Object就是最簡單的單例模式,每個相同名稱的Object其實都是一樣的,也只會有那麼一個。

Sealed class進階應用

我們可以將要對View進行操作的功能封裝為一個sealed class(這邊為UiOp),並在裡面列舉出我們將會進行的動作:

覆寫「+」號運算符,提升程式碼的易讀性:

看一下使用範例:

可以看到我們的方法run()就是對View進行操作。

進行什麼操作呢?這些操作已經用非常易讀的方式建構在ui變數了,藉由適時的使用sealed class,可以方便地讓我們進行同一個系列的所有相關操作。

--

--