R

R

Tutorial R: Sistema R6: clases referenciales y encapsulamiento

Aprende a crear clases R6 en R con encapsulamiento, métodos públicos y privados, y manejo de constructores y referencias para programación avanzada.

Aprende R y certifícate

Clases R6 con encapsulamiento

El sistema R6 en R introduce un enfoque diferente para la programación orientada a objetos, permitiendo crear clases referenciales con verdadero encapsulamiento. A diferencia de los sistemas S3 y S4 que son más comunes en R, las clases R6 funcionan por referencia en lugar de por valor, lo que significa que los objetos pueden ser modificados en su lugar sin necesidad de reasignación.

Para trabajar con clases R6, primero necesitamos instalar y cargar el paquete R6:

# Instalación (solo necesario una vez)
install.packages("R6")

# Cargar el paquete
library(R6)

Creación de una clase R6 básica

La estructura básica de una clase R6 se define mediante la función R6Class(). Veamos un ejemplo sencillo:

Persona <- R6Class(
  classname = "Persona",
  public = list(
    nombre = NULL,
    edad = NULL,
    
    initialize = function(nombre, edad) {
      self$nombre <- nombre
      self$edad <- edad
    },
    
    presentarse = function() {
      cat("Hola, me llamo", self$nombre, "y tengo", self$edad, "años.\n")
    }
  )
)

En este ejemplo, hemos creado una clase llamada Persona con:

  • Dos propiedades públicas: nombre y edad
  • Un constructor (initialize) que inicializa estas propiedades
  • Un método público llamado presentarse

Para crear una instancia de esta clase y utilizarla:

# Crear una nueva persona
ana <- Persona$new(nombre = "Ana", edad = 28)

# Acceder a propiedades
ana$nombre  # "Ana"
ana$edad    # 28

# Llamar a un método
ana$presentarse()  # "Hola, me llamo Ana y tengo 28 años."

# Modificar una propiedad
ana$edad <- 29
ana$presentarse()  # "Hola, me llamo Ana y tengo 29 años."

Encapsulamiento con campos privados

Una de las ventajas principales del sistema R6 es la capacidad de implementar verdadero encapsulamiento mediante campos y métodos privados. Estos elementos solo son accesibles desde dentro de la clase, no desde el exterior.

Veamos cómo implementar una clase con encapsulamiento:

CuentaBancaria <- R6Class(
  classname = "CuentaBancaria",
  
  # Campos privados
  private = list(
    saldo = 0,
    historial = list(),
    
    registrar_movimiento = function(tipo, monto) {
      movimiento <- list(
        fecha = Sys.time(),
        tipo = tipo,
        monto = monto,
        saldo_resultante = private$saldo
      )
      private$historial <- c(private$historial, list(movimiento))
    }
  ),
  
  # Interfaz pública
  public = list(
    titular = NULL,
    
    initialize = function(titular, saldo_inicial = 0) {
      self$titular <- titular
      private$saldo <- saldo_inicial
      private$registrar_movimiento("apertura", saldo_inicial)
    },
    
    depositar = function(monto) {
      if (monto <= 0) {
        stop("El monto a depositar debe ser positivo")
      }
      private$saldo <- private$saldo + monto
      private$registrar_movimiento("depósito", monto)
      invisible(self)
    },
    
    retirar = function(monto) {
      if (monto <= 0) {
        stop("El monto a retirar debe ser positivo")
      }
      if (monto > private$saldo) {
        stop("Saldo insuficiente")
      }
      private$saldo <- private$saldo - monto
      private$registrar_movimiento("retiro", monto)
      invisible(self)
    },
    
    consultar_saldo = function() {
      return(private$saldo)
    },
    
    ver_estado = function() {
      cat("Cuenta de:", self$titular, "\n")
      cat("Saldo actual:", private$saldo, "\n")
    }
  )
)

En este ejemplo más elaborado:

  • Hemos definido campos privados (saldo e historial) que no son accesibles directamente desde fuera de la clase
  • Creamos un método privado (registrar_movimiento) que solo puede ser llamado por otros métodos de la clase
  • La interfaz pública proporciona métodos controlados para interactuar con los datos privados

Veamos cómo se utiliza esta clase:

# Crear una cuenta
cuenta_maria <- CuentaBancaria$new(titular = "María López", saldo_inicial = 1000)

# Realizar operaciones
cuenta_maria$depositar(500)
cuenta_maria$retirar(200)

# Consultar estado
cuenta_maria$ver_estado()  # Muestra titular y saldo actual

# Intentar acceder a un campo privado (generará un error)
# cuenta_maria$saldo  # Error: campo 'saldo' no existe
# cuenta_maria$historial  # Error: campo 'historial' no existe

# La única forma de conocer el saldo es mediante el método público
saldo_actual <- cuenta_maria$consultar_saldo()
print(saldo_actual)  # 1300

Ventajas del encapsulamiento en R6

El encapsulamiento que ofrece R6 proporciona varias ventajas importantes:

  • Protección de datos: Los datos internos están protegidos contra modificaciones accidentales o no autorizadas
  • Validación centralizada: Podemos implementar reglas de validación en los métodos públicos (como verificar que los montos sean positivos)
  • Abstracción: Los usuarios de la clase solo necesitan conocer la interfaz pública, no los detalles de implementación
  • Mantenimiento simplificado: Podemos modificar la implementación interna sin afectar el código que utiliza la clase

Encadenamiento de métodos

Otra característica útil de R6 es la posibilidad de encadenar métodos. Esto se logra haciendo que los métodos devuelvan invisible(self):

# Encadenamiento de métodos
cuenta_maria$depositar(100)$retirar(50)$ver_estado()

Este patrón permite escribir código más conciso y legible cuando se realizan múltiples operaciones sobre el mismo objeto.

Consideraciones sobre el diseño de clases con encapsulamiento

Al diseñar clases R6 con encapsulamiento, es recomendable seguir estos principios:

  • Hacer privado por defecto: Solo exponer como público lo que realmente necesita ser accesible desde fuera
  • Proporcionar métodos de acceso controlados en lugar de exponer directamente las propiedades
  • Implementar validación en los métodos que modifican el estado interno
  • Mantener la coherencia interna utilizando métodos privados para operaciones comunes

El encapsulamiento es uno de los pilares fundamentales de la programación orientada a objetos, y el sistema R6 nos permite implementarlo de manera efectiva en R, proporcionando una estructura más robusta para nuestros programas.

Métodos públicos y privados

En el sistema R6, la distinción entre métodos públicos y métodos privados es fundamental para implementar un buen diseño orientado a objetos. Esta separación permite controlar qué funcionalidades están disponibles para los usuarios de la clase y cuáles permanecen como parte de la implementación interna.

Los métodos públicos forman la interfaz de la clase, mientras que los métodos privados encapsulan la lógica interna que no necesita ser expuesta. Esta organización ayuda a crear código más mantenible y robusto.

Definición de métodos públicos

Los métodos públicos se definen dentro del argumento public de la función R6Class(). Estos métodos son accesibles directamente desde cualquier instancia de la clase:

Calculadora <- R6Class(
  classname = "Calculadora",
  public = list(
    valor = 0,
    
    sumar = function(x) {
      self$valor <- self$valor + x
      invisible(self)
    },
    
    restar = function(x) {
      self$valor <- self$valor - x
      invisible(self)
    },
    
    obtener_valor = function() {
      return(self$valor)
    }
  )
)

# Uso de métodos públicos
calc <- Calculadora$new()
calc$sumar(5)
calc$restar(2)
resultado <- calc$obtener_valor()
print(resultado)  # 3

En este ejemplo, sumar(), restar() y obtener_valor() son métodos públicos que cualquier usuario de la clase puede invocar.

Definición de métodos privados

Los métodos privados se definen dentro del argumento private y solo son accesibles desde dentro de la clase, utilizando la referencia private:

Estadisticas <- R6Class(
  classname = "Estadisticas",
  private = list(
    datos = NULL,
    
    validar_datos = function() {
      if (is.null(private$datos) || length(private$datos) == 0) {
        stop("No hay datos para analizar")
      }
    },
    
    calcular_suma = function() {
      private$validar_datos()
      return(sum(private$datos))
    }
  ),
  
  public = list(
    initialize = function(datos = NULL) {
      private$datos <- datos
    },
    
    agregar_datos = function(nuevos_datos) {
      private$datos <- c(private$datos, nuevos_datos)
      invisible(self)
    },
    
    media = function() {
      private$validar_datos()
      return(private$calcular_suma() / length(private$datos))
    },
    
    suma = function() {
      return(private$calcular_suma())
    }
  )
)

En este ejemplo:

  • validar_datos() y calcular_suma() son métodos privados que solo pueden ser llamados desde otros métodos de la clase
  • agregar_datos(), media() y suma() son métodos públicos que forman la interfaz de la clase

Patrones de uso de métodos privados

Los métodos privados son especialmente útiles para implementar varios patrones de diseño:

  • Validación centralizada: Crear métodos privados para validar entradas o estados
GestorArchivos <- R6Class(
  classname = "GestorArchivos",
  private = list(
    verificar_archivo = function(ruta) {
      if (!file.exists(ruta)) {
        stop("El archivo no existe: ", ruta)
      }
      if (!file.access(ruta, 4) == 0) {
        stop("No se puede leer el archivo: ", ruta)
      }
    }
  ),
  public = list(
    leer_texto = function(ruta) {
      private$verificar_archivo(ruta)
      return(readLines(ruta))
    },
    
    leer_datos = function(ruta, header = TRUE) {
      private$verificar_archivo(ruta)
      return(read.csv(ruta, header = header))
    }
  )
)
  • Lógica compartida: Extraer código común a varios métodos públicos
Inventario <- R6Class(
  classname = "Inventario",
  private = list(
    items = list(),
    
    buscar_item = function(id) {
      for (i in seq_along(private$items)) {
        if (private$items[[i]]$id == id) {
          return(i)
        }
      }
      return(NULL)
    }
  ),
  public = list(
    agregar = function(id, nombre, cantidad) {
      if (!is.null(private$buscar_item(id))) {
        stop("Ya existe un item con ese ID")
      }
      
      nuevo_item <- list(
        id = id,
        nombre = nombre,
        cantidad = cantidad
      )
      
      private$items <- c(private$items, list(nuevo_item))
      invisible(self)
    },
    
    actualizar_cantidad = function(id, nueva_cantidad) {
      indice <- private$buscar_item(id)
      if (is.null(indice)) {
        stop("Item no encontrado")
      }
      
      private$items[[indice]]$cantidad <- nueva_cantidad
      invisible(self)
    },
    
    obtener_item = function(id) {
      indice <- private$buscar_item(id)
      if (is.null(indice)) {
        return(NULL)
      }
      return(private$items[[indice]])
    }
  )
)

Convenciones de nomenclatura

Es recomendable seguir algunas convenciones para nombrar los métodos:

  • Usar verbos para los métodos que realizan acciones: calcular_total(), validar_entrada()
  • Usar sustantivos para los métodos que devuelven valores: media(), total()
  • Prefijos como es_ o tiene_ para métodos que devuelven valores lógicos: es_valido(), tiene_elementos()
Producto <- R6Class(
  classname = "Producto",
  private = list(
    precio_base = 0,
    descuento = 0,
    
    calcular_precio_final = function() {
      return(private$precio_base * (1 - private$descuento))
    }
  ),
  public = list(
    initialize = function(precio) {
      private$precio_base <- precio
    },
    
    establecer_descuento = function(porcentaje) {
      if (porcentaje < 0 || porcentaje > 1) {
        stop("El descuento debe estar entre 0 y 1")
      }
      private$descuento <- porcentaje
      invisible(self)
    },
    
    precio = function() {
      return(private$calcular_precio_final())
    },
    
    tiene_descuento = function() {
      return(private$descuento > 0)
    }
  )
)

Métodos con comportamiento condicional

Los métodos pueden implementar comportamientos condicionales basados en el estado interno del objeto:

Temporizador <- R6Class(
  classname = "Temporizador",
  private = list(
    tiempo_inicio = NULL,
    tiempo_fin = NULL,
    
    verificar_iniciado = function() {
      if (is.null(private$tiempo_inicio)) {
        stop("El temporizador no ha sido iniciado")
      }
    }
  ),
  public = list(
    iniciar = function() {
      if (!is.null(private$tiempo_inicio)) {
        warning("El temporizador ya estaba iniciado. Reiniciando.")
      }
      private$tiempo_inicio <- Sys.time()
      private$tiempo_fin <- NULL
      invisible(self)
    },
    
    detener = function() {
      private$verificar_iniciado()
      if (!is.null(private$tiempo_fin)) {
        warning("El temporizador ya estaba detenido")
        return(invisible(self))
      }
      private$tiempo_fin <- Sys.time()
      invisible(self)
    },
    
    tiempo_transcurrido = function() {
      private$verificar_iniciado()
      fin <- private$tiempo_fin
      if (is.null(fin)) {
        fin <- Sys.time()
      }
      return(difftime(fin, private$tiempo_inicio, units = "secs"))
    },
    
    esta_activo = function() {
      return(!is.null(private$tiempo_inicio) && is.null(private$tiempo_fin))
    }
  )
)

Métodos que retornan self para encadenamiento

Como vimos brevemente, podemos implementar métodos encadenables haciendo que devuelvan invisible(self):

Texto <- R6Class(
  classname = "Texto",
  public = list(
    contenido = "",
    
    agregar = function(texto) {
      self$contenido <- paste0(self$contenido, texto)
      invisible(self)
    },
    
    agregar_linea = function(texto) {
      if (self$contenido != "") {
        self$contenido <- paste0(self$contenido, "\n")
      }
      self$contenido <- paste0(self$contenido, texto)
      invisible(self)
    },
    
    limpiar = function() {
      self$contenido <- ""
      invisible(self)
    },
    
    mostrar = function() {
      cat(self$contenido, "\n")
      invisible(self)
    }
  )
)

# Uso con encadenamiento
documento <- Texto$new()
documento$agregar("Hola ")$agregar("mundo")$agregar_linea("Esto es R6")$mostrar()

Este patrón permite escribir código más fluido y legible, especialmente cuando se realizan múltiples operaciones secuenciales sobre un mismo objeto.

La combinación efectiva de métodos públicos y privados es clave para crear clases R6 bien diseñadas que sean fáciles de usar y mantener.

Constructores y referencias

En el sistema R6, los constructores y el manejo de referencias son elementos fundamentales que lo distinguen de otros sistemas de orientación a objetos en R. Estos conceptos son esenciales para comprender cómo funcionan los objetos R6 y cómo aprovechar su naturaleza mutable.

El constructor initialize

El constructor en R6 es un método especial llamado initialize que se ejecuta automáticamente cuando creamos una nueva instancia de la clase. Este método permite configurar el estado inicial del objeto:

Rectangulo <- R6Class(
  classname = "Rectangulo",
  public = list(
    ancho = NULL,
    alto = NULL,
    
    initialize = function(ancho = 1, alto = 1) {
      self$ancho <- ancho
      self$alto <- alto
    }
  )
)

# Creación de instancias usando el constructor
rect1 <- Rectangulo$new(5, 3)
rect2 <- Rectangulo$new(ancho = 10)  # alto tomará el valor por defecto (1)

El constructor tiene varias características importantes:

  • Puede tener parámetros con valores predeterminados, lo que permite crear objetos con configuraciones parciales
  • Utiliza self$ para referirse a las propiedades del objeto que se está creando
  • Puede realizar validaciones o cálculos iniciales
Circulo <- R6Class(
  classname = "Circulo",
  public = list(
    radio = NULL,
    
    initialize = function(radio) {
      if (radio <= 0) {
        stop("El radio debe ser un valor positivo")
      }
      self$radio <- radio
    },
    
    area = function() {
      return(pi * self$radio^2)
    }
  )
)

# El constructor valida los parámetros
circulo <- Circulo$new(5)
# circulo_invalido <- Circulo$new(-2)  # Generaría un error

Naturaleza referencial de R6

A diferencia de la mayoría de los objetos en R, que se copian cuando se asignan a nuevas variables, los objetos R6 funcionan por referencia. Esto significa que cuando asignamos un objeto R6 a una nueva variable, ambas variables apuntan al mismo objeto en memoria:

contador <- R6Class(
  classname = "Contador",
  public = list(
    valor = 0,
    
    incrementar = function() {
      self$valor <- self$valor + 1
      invisible(self)
    }
  )
)

# Creamos un contador
c1 <- Contador$new()
c1$incrementar()
print(c1$valor)  # 1

# Asignamos a una nueva variable
c2 <- c1
c2$incrementar()

# Ambas variables reflejan el cambio
print(c1$valor)  # 2
print(c2$valor)  # 2

Esta característica tiene implicaciones importantes:

  • Los cambios realizados a través de cualquier referencia afectan al mismo objeto
  • No es necesario reasignar el objeto después de modificarlo
  • Permite implementar patrones de diseño que requieren identidad de objetos

Comparación con comportamiento por valor

Para entender mejor la naturaleza referencial, comparemos con el comportamiento típico de R (por valor):

# Comportamiento normal de R (por valor)
lista_normal <- list(valor = 10)
copia_lista <- lista_normal
copia_lista$valor <- 20

print(lista_normal$valor)  # 10 (no cambia)
print(copia_lista$valor)   # 20

# Comportamiento de R6 (por referencia)
objeto_r6 <- Contador$new()
objeto_r6$valor <- 10
referencia_r6 <- objeto_r6
referencia_r6$valor <- 20

print(objeto_r6$valor)     # 20 (cambia)
print(referencia_r6$valor) # 20

Creación de referencias explícitas

En ocasiones, necesitamos que un objeto R6 mantenga una referencia a otro objeto R6. Esto permite crear relaciones entre objetos:

Autor <- R6Class(
  classname = "Autor",
  public = list(
    nombre = NULL,
    
    initialize = function(nombre) {
      self$nombre <- nombre
    }
  )
)

Libro <- R6Class(
  classname = "Libro",
  public = list(
    titulo = NULL,
    autor = NULL,  # Referencia a un objeto Autor
    
    initialize = function(titulo, autor) {
      self$titulo <- titulo
      self$autor <- autor
    },
    
    info = function() {
      cat(self$titulo, "escrito por", self$autor$nombre, "\n")
    }
  )
)

# Creamos un autor
garcia_marquez <- Autor$new("Gabriel García Márquez")

# Creamos libros que referencian al mismo autor
libro1 <- Libro$new("Cien años de soledad", garcia_marquez)
libro2 <- Libro$new("El amor en los tiempos del cólera", garcia_marquez)

# Si cambiamos el nombre del autor, se refleja en todos los libros
garcia_marquez$nombre <- "Gabriel García Márquez (Premio Nobel)"
libro1$info()  # Muestra el nombre actualizado
libro2$info()  # También muestra el nombre actualizado

Constructores personalizados

Además del constructor estándar initialize, podemos crear métodos de fábrica (factory methods) que actúen como constructores alternativos:

Punto <- R6Class(
  classname = "Punto",
  public = list(
    x = 0,
    y = 0,
    
    initialize = function(x = 0, y = 0) {
      self$x <- x
      self$y <- y
    }
  )
)

# Añadimos métodos de fábrica como funciones externas
crear_punto_polar <- function(radio, angulo) {
  x <- radio * cos(angulo)
  y <- radio * sin(angulo)
  return(Punto$new(x, y))
}

# Uso del constructor personalizado
p <- crear_punto_polar(5, pi/4)
cat("Coordenadas:", p$x, p$y, "\n")

También podemos implementar métodos de fábrica como métodos estáticos dentro de la clase:

Fecha <- R6Class(
  classname = "Fecha",
  public = list(
    dia = NULL,
    mes = NULL,
    anio = NULL,
    
    initialize = function(dia, mes, anio) {
      self$dia <- dia
      self$mes <- mes
      self$anio <- anio
    },
    
    formato = function() {
      return(sprintf("%02d/%02d/%04d", self$dia, self$mes, self$anio))
    }
  )
)

# Añadimos un método de fábrica como atributo de la clase
Fecha$hoy <- function() {
  fecha_actual <- as.POSIXlt(Sys.Date())
  return(Fecha$new(
    fecha_actual$mday,
    fecha_actual$mon + 1,  # En POSIXlt los meses van de 0 a 11
    fecha_actual$year + 1900  # En POSIXlt los años son relativos a 1900
  ))
}

# Uso del método de fábrica
fecha_actual <- Fecha$hoy()
cat("Hoy es:", fecha_actual$formato(), "\n")

Manejo de referencias circulares

En ocasiones, podemos necesitar que dos objetos se referencien mutuamente. Esto crea una referencia circular que debemos manejar con cuidado:

Departamento <- R6Class("Departamento")  # Declaración adelantada

Empleado <- R6Class(
  classname = "Empleado",
  public = list(
    nombre = NULL,
    departamento = NULL,
    
    initialize = function(nombre) {
      self$nombre <- nombre
    },
    
    asignar_departamento = function(depto) {
      self$departamento <- depto
      depto$agregar_empleado(self)
      invisible(self)
    }
  )
)

# Completamos la definición de Departamento
Departamento <- R6Class(
  classname = "Departamento",
  public = list(
    nombre = NULL,
    empleados = NULL,
    
    initialize = function(nombre) {
      self$nombre <- nombre
      self$empleados <- list()
    },
    
    agregar_empleado = function(emp) {
      # Evitamos duplicados
      for (e in self$empleados) {
        if (identical(e, emp)) return(invisible(self))
      }
      self$empleados <- c(self$empleados, list(emp))
      invisible(self)
    }
  )
)

# Creamos las instancias
rrhh <- Departamento$new("Recursos Humanos")
juan <- Empleado$new("Juan Pérez")

# Establecemos la referencia circular
juan$asignar_departamento(rrhh)

# Verificamos las referencias
cat("Departamento de Juan:", juan$departamento$nombre, "\n")
cat("Primer empleado de RRHH:", rrhh$empleados[[1]]$nombre, "\n")

Consideraciones sobre el rendimiento

El sistema de referencias de R6 tiene implicaciones en el rendimiento:

  • Ventaja: Evita copias innecesarias de objetos grandes, lo que puede mejorar el rendimiento
  • Consideración: Las referencias circulares pueden impedir la liberación automática de memoria
# Ejemplo de rendimiento con objetos grandes
crear_matriz_grande <- function(n) {
  return(matrix(rnorm(n*n), n, n))
}

ContenedorDatos <- R6Class(
  classname = "ContenedorDatos",
  public = list(
    datos = NULL,
    
    initialize = function(datos) {
      self$datos <- datos
    },
    
    procesar = function() {
      # Operación que modifica los datos in-situ
      self$datos <- self$datos * 2
      invisible(self)
    }
  )
)

# Con objetos grandes, la naturaleza referencial es más eficiente
matriz_grande <- crear_matriz_grande(1000)
contenedor <- ContenedorDatos$new(matriz_grande)
contenedor$procesar()  # Modifica los datos sin crear copias

Resumen de buenas prácticas

Al trabajar con constructores y referencias en R6:

  • Diseña constructores claros con parámetros nombrados y valores predeterminados
  • Realiza validaciones en el constructor para garantizar que el objeto comience en un estado válido
  • Ten en cuenta la naturaleza referencial al diseñar la interacción entre objetos
  • Utiliza métodos de fábrica para proporcionar formas alternativas de crear objetos
  • Maneja con cuidado las referencias circulares para evitar problemas de memoria

El sistema de constructores y referencias de R6 proporciona una flexibilidad que permite implementar patrones de diseño orientados a objetos más complejos y eficientes que los sistemas tradicionales de R.

Aprende R online

Otros ejercicios de programación de R

Evalúa tus conocimientos de esta lección Sistema R6: clases referenciales y encapsulamiento con nuestros retos de programación de tipo Test, Puzzle, Código y Proyecto con VSCode, guiados por IA.

Todas las lecciones de R

Accede a todas las lecciones de R y aprende con ejemplos prácticos de código y ejercicios de programación con IDE web sin instalar nada.

Instalación De R Y Rstudio

R

Introducción Y Entorno

Introducción A R

R

Introducción Y Entorno

Operadores

R

Sintaxis

Estructuras De Datos

R

Sintaxis

Funciones

R

Sintaxis

Estructuras De Control Iterativo

R

Sintaxis

Scopes Y Closures

R

Sintaxis

Estructuras De Control Condicional

R

Sintaxis

Funciones Anónimas

R

Sintaxis

Tipos De Datos Y Variables

R

Sintaxis

Sistema R6: Clases Referenciales Y Encapsulamiento

R

Programación Orientada A Objetos

Sistema S4: Clases Formales Y Validación

R

Programación Orientada A Objetos

Herencia Y Polimorfismo En R

R

Programación Orientada A Objetos

Sistemas De Oop En R

R

Programación Orientada A Objetos

Sistema S3: Clases Implícitas Y Métodos Genéricos

R

Programación Orientada A Objetos

Tidyverse Para Transformación De Datos

R

Manipulación De Datos

Lubridate Para Fechas Y Tiempo

R

Manipulación De Datos

Group_by Y Summarize Para Agrupación Y Resumen

R

Manipulación De Datos

Stringr Para Expresiones Regulares

R

Manipulación De Datos

Tidyr Para Limpieza De Valores Faltantes

R

Manipulación De Datos

Joins En R Para Combinación Y Relaciones De Tablas

R

Manipulación De Datos

Pivot_longer Y Pivot_wider Para Reestructuración

R

Manipulación De Datos

Mutate Y Transmute Para Transformación

R

Manipulación De Datos

Dplyr Para Filtrado Y Selección

R

Manipulación De Datos

Readr Y Read.csv Para Importar Datos

R

Manipulación De Datos

Gráficos Bivariantes En R

R

Visualización De Datos

Gráficos Univariantes En R

R

Visualización De Datos

Facetas En Ggplot2

R

Visualización De Datos

Personalización Y Temas

R

Visualización De Datos

Ggplot2 Para Visualización De Datos

R

Visualización De Datos

Gráficos Multivariantes En R

R

Visualización De Datos

Correlación En R

R

Estadística

Regresión Lineal En R

R

Estadística

Pruebas De Hipótesis En R

R

Estadística

Anova En R

R

Estadística

Estadística Descriptiva En R

R

Estadística

Accede GRATIS a R y certifícate

En esta lección

Objetivos de aprendizaje de esta lección

  • Comprender la estructura y creación de clases R6 en R.
  • Implementar encapsulamiento mediante campos y métodos privados.
  • Diferenciar entre métodos públicos y privados y su uso adecuado.
  • Entender el funcionamiento de constructores y la naturaleza referencial de los objetos R6.
  • Aplicar buenas prácticas en el diseño de clases R6 y manejo de referencias, incluyendo referencias circulares.