Trong bài viết này, bạn sẽ tìm hiểu về Sealed class, cách chúng được tạo ra và khi nào cần sử dụng chúng với sự trợ giúp của các ví dụ.

Các sealed class được sử dụng khi một giá trị chỉ có thể có một trong các kiểu từ một tập hợp giới hạn (cấu trúc phân cấp bị hạn chế).

Trước khi đi vào chi tiết về các sealed class, hãy cùng khám phá xem chúng giải quyết vấn đề gì. Hãy lấy một ví dụ (lấy từ trang web chính thức của Kotlin – bài báo về các sealed class ):

/*
Cafedev.vn - Kênh thông tin IT hàng đầu Việt Nam
@author cafedevn
Contact: cafedevn@gmail.com
Fanpage: https://www.facebook.com/cafedevn
Group: https://www.facebook.com/groups/cafedev.vn/
Instagram: https://instagram.com/cafedevn
Twitter: https://twitter.com/CafedeVn
Linkedin: https://www.linkedin.com/in/cafe-dev-407054199/
Pinterest: https://www.pinterest.com/cafedevvn/
YouTube: https://www.youtube.com/channel/UCE7zpY_SlHGEgo67pHxqIoA/
*/

class Expr
class Const(val value: Int) : Expr
class Sum(val left: Expr, val right: Expr) : Expr

fun eval(e: Expr): Int =
        when (e) {
            is Const -> e.value
            is Sum -> eval(e.right) + eval(e.left)
            else ->
                throw IllegalArgumentException("Unknown expression")
        }

Trong chương trình trên, class cơ sở Expr có hai class dẫn xuất là constant (đại diện cho một số) và sum (biểu diễn tổng của hai biểu thức). Ở đây, bắt buộc phải sử dụng nhánh  else cho điều kiện mặc định trong  biểu thức when .

Bây giờ, nếu bạn lấy một subclass mới từ class Expr, trình biên dịch sẽ không phát hiện ra bất kỳ thứ gì khi else nhánh xử lý nó, và điều này có thể dẫn đến lỗi. Sẽ tốt hơn nếu trình biên dịch phát lỗi khi chúng ta thêm một subclass mới.

Để giải quyết vấn đề này, bạn có thể sử dụng sealed class. Như đã đề cập, sealed class hạn chế khả năng tạo các subclass. Và, khi bạn xử lý tất cả các subclass của một sealed class trong một biểu thức when, sẽ không cần thiết phải sử dụng nhánh else.

Để tạo một sealed class, ta sử dụng công cụ sửa đổi seal. Ví dụ,

sealed class Expr

1. Ví dụ về sealed class

Dưới đây là cách bạn có thể giải quyết vấn đề trên bằng cách sử dụng sealed class:

sealed class Expr
class Const(val value: Int) : Expr()
class Sum(val left: Expr, val right: Expr) : Expr()
object NotANumber : Expr()


fun eval(e: Expr): Int =
        when (e) {
            is Const -> e.value
            is Sum -> eval(e.right) + eval(e.left)
            NotANumber -> java.lang.Double.NaN
        }

Như bạn thấy, không hề có nhánh else. Nếu bạn lấy một subclass mới từ class Expr, trình biên dịch sẽ báo lỗi trừ khi subclass được xử lý trong biểu thức when.

2. Một số lưu ý quan trọng

  • Tất cả các subclass của một sealed class phải được khai báo trong cùng một tệp và tệp này là nơi khai báo sealed class.
  • Bản thân một sealed class là trừu tượng và bạn không thể khởi tạo các đối tượng từ nó.
  • Bạn không thể tạo các hàm tạo không riêng tư của một sealed class; các hàm tạo của chúng là private theo mặc định.

3. Sự khác biệt giữa Enum và Sealed Class

Enum class và sealed class khá giống nhau. Tập hợp các giá trị cho một kiểu enum cũng bị hạn chế giống như một sealed class.

Sự khác biệt duy nhất là, enum có thể chỉ có một instance duy nhất, trong khi một subclass của một sealed class có thể có nhiều instance.

Tài liệu từ cafedev:

Nếu bạn thấy hay và hữu ích, bạn có thể tham gia các kênh sau của cafedev để nhận được nhiều hơn nữa:

Chào thân ái và quyết thắng!

Đăng ký kênh youtube để ủng hộ Cafedev nha các bạn, Thanks you!