Saltar al contenido

clase sellada vs enumeración cuando se usa el tipo asociado

Ya no tienes que indagar más por otros sitios ya que estás al lugar exacto, contamos con la solución que buscas pero sin problema.

Solución:

A sealed la clase es “una extensión de las clases de enumeración”. Pueden existir en Múltiples instancias que contienen estado, mientras que cada constante de enumeración existe solo como una única instancia.

Dado que, en su ejemplo, no es necesario que se creen instancias de los valores varias veces y no proporcionan un comportamiento especial, enumeraciones debería ser adecuado para el caso de uso.

Además, consulte los documentos.

Analicemos la diferencia entre enumeraciones y clases selladas en varios aspectos con ejemplos contrastantes. Esto lo ayudará a elegir uno sobre el otro según su caso de uso.


Propiedades

Enum

En las clases de enumeración, cada valor de enumeración no puede tener su propia propiedad única. Está obligado a tener la misma propiedad para cada valor de enumeración:

enum class DeliveryStatus(val trackingId: String?) 
    PREPARING(null),
    DISPATCHED("27211"),
    DELIVERED("27211"),

Aquí necesitamos el trackingId solo para el DISPATCHED y DELIVERED, los PREPARING se ve obligado a tener un null valor.

Clase sellada

En el caso de clases selladas, podemos tener diferentes propiedades para cada subtipo:

sealed class DeliveryStatus
class Preparing() : DeliveryStatus()
class Dispatched(val trackingId: String) : DeliveryStatus()
class Delivered(val trackingId: String, val receiversName: String) : DeliveryStatus()

Aquí tenemos diferentes propiedades para cada subtipo. Preparing no necesita propiedades para nuestro caso de uso, por lo que tenemos la flexibilidad de no especificar ninguna propiedad a diferencia de las forzadas null valores en enumeraciones. Dispatched tiene una propiedad mientras que el Delivered tiene dos propiedades.

Considerando el ejemplo Color(val value: Int) en la pregunta, tienes un común value: Int propiedad para todas las constantes y dado que no necesita propiedades diferentes para constantes diferentes, debe usar enumeraciones en este caso.


Funciones

Enum

Las enumeraciones pueden tener funciones abstractas así como funciones regulares. Pero al igual que las propiedades, cada valor de enumeración también debe tener la misma función:

enum class DeliveryStatus 
    PREPARING 
        override fun cancelOrder() = println("Cancelled successfully")
    ,
    DISPATCHED 
        override fun cancelOrder() = println("Delivery rejected")
    ,
    DELIVERED 
        override fun cancelOrder() = println("Return initiated")
    ;

    abstract fun cancelOrder()

En este ejemplo, tenemos un abstract función cancelOrder() que tenemos que override en cada valor de enumeración. Eso significa que no podemos tener diferentes funciones para diferentes valores de enumeración.

Uso:

class DeliveryManager 
    fun cancelOrder(status: DeliveryStatus) 
        status.cancelOrder()
    

Clase sellada

En clases selladas podemos tener diferentes funciones para diferentes subtipos:

sealed class DeliveryStatus

class Preparing : DeliveryStatus() 
    fun cancelOrder() = println("Cancelled successfully")


class Dispatched : DeliveryStatus() 
    fun rejectDelivery() = println("Delivery rejected")


class Delivered : DeliveryStatus() 
    fun returnItem() = println("Return initiated")

Aquí tenemos diferentes funciones: cancelOrder() por Preparing, rejectDelivery() por Dispatched y returnItem() por Delivered. Esto aclara el intent y hace que el código sea más legible, además tenemos la opción de no tener la función, en caso de que no queramos.

Uso:

class DeliveryManager 
    fun cancelOrder(status: DeliveryStatus) = when(status) 
        is Preparing -> status.cancelOrder()
        is Dispatched -> status.rejectDelivery()
        is Delivered -> status.returnItem()
    

Si queremos una función común para todos los subtipos como en el ejemplo de enumeración, podemos tenerla en la clase sellada definiéndola en la propia clase sellada y luego anulándola en los subtipos:

sealed class DeliveryStatus 
    abstract fun cancelOrder()

La ventaja de tener una función común para todos los tipos es que no tenemos que escribir check usando el is operador. Simplemente podemos usar polimorfismo como se muestra en la DeliveryManager ejemplo de clase de enumeración.


Herencia

Enum

Ya que enum los valores son objetos, no se pueden ampliar:

class LocallyDispatched : DeliveryStatus.DISPATCHED      // Error

los enum class es implícitamente final, por lo que no puede ser extendido por otras clases:

class FoodDeliveryStatus : DeliveryStatus()              // Error

Las clases de enumeración no pueden extender otras clases, solo pueden extender interfaces:

open class OrderStatus  
interface Cancellable  

enum class DeliveryStatus : OrderStatus()                // Error
enum class DeliveryStatus : Cancellable                  // OK

Clase sellada

Dado que los subtipos de clase sellada son tipos, se pueden extender:

class LocallyDispatched : Dispatched()                   // OK

¡La clase sellada en sí se puede extender, por supuesto !:

class PaymentReceived : DeliveryStatus()                   // OK

Las clases selladas pueden ampliar otras clases, así como interfaces:

open class OrderStatus  
interface Cancellable  

sealed class DeliveryStatus : OrderStatus()             // OK
sealed class DeliveryStatus : Cancellable               // OK

Numero de instancias

Enum

Dado que los valores de enumeración son objetos y no tipos, no podemos crear varias instancias de ellos:

enum class DeliveryStatus(val trackingId: String?) 
    PREPARING(null),
    DISPATCHED("27211"),
    DELIVERED("27211"),

En este ejemplo, DISPATCHED es un objeto y no un tipo, por lo que solo puede existir como una única instancia, no podemos crear más instancias a partir de él:

// Single instance
val dispatched1 = DeliveryStatus.DISPATCHED               // OK

// Another instance
val dispatched2 = DeliveryStatus.DISPATCHED("45234")      // Error

Clase sellada

Los subtipos de clases selladas son tipos, por lo que podemos crear varias instancias de estos tipos. También podemos hacer que un tipo tenga solo una instancia usando un object declaración:

sealed class DeliveryStatus
object Preparing : DeliveryStatus()
class Dispatched(val trackingId: String) : DeliveryStatus()
data class Delivered(val receiversName: String) : DeliveryStatus()

En este ejemplo, podemos crear varias instancias de Dispatched y Delivered. Observe que hemos utilizado la capacidad de los subtipos de la clase sellada para ser un singleton object, un habitual class o un data class. Preparing puede tener solo una object, al igual que un valor de enumeración:

// Multiple Instances
val dispatched1 = Dispatched("27211")                     // OK
val dispatched2 = Dispatched("45234")                     // OK

// Single Instance
val preparing1 = Preparing                                // OK
val preparing2 = Preparing()                              // Error

Observe también que en el código anterior, cada instancia de Dispatched puede tener un valor diferente para el trackingId propiedad.


Serializable y comparable

Enum

Cada enum class en Kotlin se extiende implícitamente por la clase abstracta java.lang.Enum. Entonces, todos los valores de enumeración tienen automáticamente las implementaciones para equals(), toString(), hashCode(), Serializable y Comparable. No tenemos que definirlos.

Clase sellada

Para las clases selladas, debemos definirlas manualmente o usar data class para el automatico equals(), toString() y hashcode() y luego implementar Serializable y Comparable a mano.


Rendimiento

Enum

Las enumeraciones no se recolectan basura, permanecen en la memoria durante la vida útil de su aplicación. Esto puede ser positivo o negativo.

El proceso de recolección de basura es costoso. Lo mismo es true para la creación de objetos, no queremos crear los mismos objetos una y otra vez. Entonces, con las enumeraciones, ahorra el costo de la recolección de basura y la creación de objetos. Este es el lado positivo.

La desventaja es que las enumeraciones permanecen en la memoria incluso cuando no están en uso, esto puede mantener la memoria ocupada todo el tiempo.

No necesita preocuparse por todo esto, si tiene de 100 a 200 enumeraciones en su aplicación. Pero cuando tiene más que eso, tiene que tomar una decisión sobre si debe buscar enumeraciones en función de los hechos, como la cantidad de enumeraciones, si estarán en uso todo el tiempo y la cantidad de memoria asignada a su JVM.

La comparación de valores de enumeración es más rápida en el when expresión porque debajo del capó, usa tableswitch para comparar los objetos. Entonces, para el ejemplo dado en la pregunta, se deben preferir las enumeraciones, ya que serán más rápidas en este caso.

En Android, cuando la optimización está habilitada, Proguard convierte las enumeraciones que no tienen funciones y propiedades en números enteros, por lo que obtiene la seguridad de tipos de las enumeraciones en tiempo de compilación y el rendimiento de las entradas en tiempo de ejecución.

Clase sellada

Las clases selladas son solo clases regulares con la única excepción de que deben extenderse en el mismo paquete y en la misma unidad de compilación. Entonces, su desempeño es equivalente a las clases regulares.

Los objetos de los subtipos de las clases selladas se recolectan como basura como los objetos de las clases regulares. Por lo tanto, debe asumir el costo de la recolección de basura y la creación de objetos.

Cuando tiene limitaciones de memoria baja, puede considerar el uso de clases selladas en lugar de enumeraciones, si necesita miles de objetos. Porque el recolector de basura puede liberar memoria cuando los objetos no están en uso.

Si utiliza object declaración para extender la clase sellada, los objetos actúan como singletons y no serán recolectados como basura, como enums.

La comparación de tipos de clases selladas es más lenta en when expresión porque debajo del capó usa instanceof para comparar los tipos. Sin embargo, la diferencia de velocidad entre enumeraciones y clases selladas, en este caso, es muy pequeña. Solo importa cuando se comparan miles de constantes en un bucle.


¡Eso es todo! Con suerte, esto le facilitará la elección de uno sobre el otro.

Tienes la opción de añadir valor a nuestra información asistiendo con tu veteranía en los informes.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *