Đăng nhập Tài khoản VIP

Xử lý optional errors sử dụng Kotlin Sealed classes

Trong một chương trình phần mềm thì việc chúng ta viết một hàm mà có trả về một kiểu dữ liệu thì là điều rất bình thường tuy nhiên nếu như trường hợp hàm đó có thể trả về nhiều kiểu dữ liệu hoặc lỗi nếu có thì mình tin là sẽ có nhiều cách để anh em có thể triển khai code giải quyết bài toán này.

Trong Kotlin có một khái niệm đó là Sealed Classes và chúng ta có thể áp dụng nó để giải quyết vấn đề ở trên.

Chúng ta cùng xem ví dụ sau:

private fun parse(url: String): ParsedData {
  val result = URL_PARSE_REGEX.find(url)

  if (result == null) {
    // Chúng ta làm gì trong block này? Trả về null, exception hay một object ParsedData không có data  
  }

  val mimeType = result.groupValues[2]
  val data = result.groupValues[4]

  return ParsedData(data, mimeType)
}

data class ParsedData(
  val data: String,
  val mimeType: String
)

Như các bạn thấy thì chúng ta có chút lúng túng về logic nếu trường hợp if (result == null) {}. Okay, Giờ hãy xem cách giải quyết khi dùng Sealed Classes.

Đầu tiên tạo một file ParseResult.kt với nội dung như sau:

sealed class ParseResult 

// Chúng ta sẽ tạo ra hai đối tượng là Error và ParsedData => dùng để trả về trong hàm parse bên dưới 

data class Error(val errorMessage: String) : ParseResult()

data class ParsedData(
  val data: String,
  val mimeType: String) : ParseResult()
)

và hàm parse chúng ta sẽ chỉnh lại như sau:

private fun parse(url: String): ParseResult {
  val result = URL_PARSE_REGEX.find(url)
  if (result == null) {
    return ParseResult.Error("No match found")
  }

  val mimeType = result.groupValues[2]
  val data = result.groupValues[4]

  return ParseResult.ParsedData(data, mimeType)
}

=> Các bạn có thể thấy hàm parse vẫn được thể hiện một kiểu trả về nhưng bên trong chúng ta có thể return về Error or ParseData và với hàm parse mới này thì mình tin đây là giải pháp ổn nhất. Chúng ta cũng hãy xem một trường hợp nữa khi kết hợp Sealed Classes với When()

val result = parse(url)
when (result) {
  is ParseResult.ParsedData -> doSomethingWithData(result.mimeType)
  is ParseResult.Error -> handleError(result.errorMessage)
}


✅ Như vậy với việc sử dụng Sealed Classes giúp chúng ta có thể dễ dàng giải quyết các trường hợp trả về nhiều loại data khác nhau + việc định nghĩa các kiểu dữ liệu mới cũng hết sức đơn giản.