¿Cómo calcular el área de cualquier figura con S3 en R 📊?
Hoy te mostraremos cómo usar el sistema de programación orientada a objetos S3 de R para crear una solución elegante y escalable.
El Problema: Un método para cada figura 🧩
Quizás empezaste definiendo funciones para cada figura, donde cada objeto contenía su propia lógica de cálculo, como en el siguiente ejemplo:
# Ejemplo de un enfoque no-S3
Circle <- function(radius) {
structure(
list(
radius = radius,
get_area = function() {
return(pi * radius^2)
}
),
class = "Circle"
)
}
# Y así para cada figura...
Si bien esto funciona, no es escalable. ¿Qué pasa si añades un pentágono o un hexágono? Tendrías que seguir definiendo nuevas funciones get_area para cada nueva clase.
La verdadera belleza del polimorfismo en R radica en crear una sola función que sepa cómo actuar de manera diferente según el objeto que reciba.
La Solución: Sobrecarga de Métodos con S3 💡
La solución S3 es simple y potente. Se basa en tres componentes:
Constructores: Funciones que crean un objeto y le asignan una clase.
Función Genérica: Una sola función
get_area()que es la interfaz pública.Métodos Específicos: Funciones que tienen la lógica para cada clase (
get_area.Circle,get_area.Square, etc.).
Paso 1: Define las Clases y sus Constructores
Primero, creamos funciones que simplemente construyen los objetos. La clave es la función structure(), que crea una lista y le asigna una clase que luego usaremos para la sobrecarga.
# Clase para Círculo
Circle <- function(radius) {
structure(list(radius = radius), class = "Circle")
}
# Clase para Cuadrado
Square <- function(side) {
structure(list(side = side), class = "Square")
}
# Clase para Triángulo
Triangle <- function(base, height) {
structure(list(base = base, height = height), class = "Triangle")
}
Paso 2: La Función Genérica get_area()
Aquí es donde entra la magia. La función get_area() es nuestra interfaz principal. El comando UseMethod("get_area") es el que le dice a R que, dependiendo de la clase del objeto que se le pase, debe encontrar y ejecutar el método correcto.
# La función genérica. R la usará para "despachar" la llamada.
get_area <- function(x) {
UseMethod("get_area")
}
Paso 3: Los Métodos Específicos para cada Clase
Ahora, definimos las funciones que realmente hacen el cálculo. S3 las reconoce por su convención de nombres: nombre_generico.nombre_de_clase.
# Método para la clase 'Circle'
get_area.Circle <- function(x) {
return(pi * x$radius^2)
}
# Método para la clase 'Square'
get_area.Square <- function(x) {
return(x$side^2)
}
# Método para la clase 'Triangle'
get_area.Triangle <- function(x) {
return(0.5 * x$base * x$height)
}
¡Listo! Ahora puedes calcular el área de cualquier figura simplemente llamando a get_area(), y R se encargará de usar la fórmula correcta.
Verificación de la Lógica con testthat ✅
La mejor manera de confirmar que nuestro código funciona es con pruebas automatizadas. El paquete testthat nos permite hacer esto de forma limpia y legible.
# Carga la librería de pruebas
library(testthat)
# Agrupa las pruebas relacionadas
describe("Función genérica get_area()", {
# Caso de prueba para el círculo
it("debería calcular correctamente el área de un círculo", {
circle <- Circle(5)
expect_equal(get_area(circle), pi * 5^2)
})
# Caso de prueba para el cuadrado
it("debería calcular correctamente el área de un cuadrado", {
square <- Square(4)
expect_equal(get_area(square), 16)
})
# Caso de prueba para el triángulo
it("debería calcular correctamente el área de un triángulo", {
triangle <- Triangle(6, 4)
expect_equal(get_area(triangle), 12)
})
# Un caso de prueba para manejar valores extremos
it("debería manejar correctamente valores cero", {
square_zero <- Square(0)
expect_equal(get_area(square_zero), 0)
triangle_zero <- Triangle(0, 5)
expect_equal(get_area(triangle_zero), 0)
})
})
El código de prueba es fácil de leer, casi como una oración: "Describe el método get_area(), y asegúrate de que debería calcular correctamente el área de un círculo". Es la manera perfecta de garantizar que tu lógica sea robusta.
Conclusión: Código Elegante y Escalable
El enfoque S3 te permite escribir código más limpio, legible y escalable. En lugar de tener múltiples funciones o métodos anidados, tienes una única interfaz (get_area) que funciona para todas tus clases. Esto no solo te ahorra tiempo, sino que también facilita que otros desarrolladores entiendan tu código.
¿Qué otro concepto de tu día a día podrías modelar usando la programación orientada a objetos en R? ¡Déjanos tu idea en los comentarios!
Comentarios
Publicar un comentario