Objetos vs Estructuras de Datos
Los objetos ocultan datos detrás del comportamiento. Las estructuras exponen datos. Mezclar ambos crea híbridos que nadie quiere.
La Diferencia Fundamental
Los objetos ocultan sus datos y exponen comportamiento (métodos). Las estructuras de datos exponen sus datos y no tienen comportamiento significativo. Esto no es estético — determina cómo tu código maneja el cambio. Añadir una nueva operación en un mundo de estructuras es fácil (añade una función). Añadir un nuevo tipo en un mundo de objetos es fácil (añade una subclase). Cada uno es difícil para el otro caso.
// Data Structure — expose data, no behavior
struct Point:
x
y
// Operates on data structures (procedural)
function distance(p):
return sqrt(p.x * p.x + p.y * p.y)
// ─────────────────────────────────────────────
// Object — hides data, exposes behavior
class Point:
_x = 0
_y = 0
function distanceToOrigin():
return sqrt(_x * _x + _y * _y)
function translate(dx, dy):
return new Point(_x + dx, _y + dy)La Ley de Deméter
Un método solo debe llamar a métodos de: sí mismo, sus argumentos, objetos que creó, o sus componentes directos. Nunca atravieses un objeto para obtener otro objeto y llamar a ese. Los choques de trenes — a.getB().getC().doSomething() — exponen detalles de implementación a lo largo de toda la cadena y hacen que el refactoring sea una pesadilla.
Choque de trenes — viola la Ley de Deméter
amount = order.getCustomer()
.getWallet().getBalance()
if order.getCustomer()
.getWallet().getBalance()
> order.total:
order.getCustomer()
.getWallet().deduct(order.total)
Dile, no preguntes — delega al propietario correcto
order.chargeCustomer()
// Inside Order:
function chargeCustomer():
customer.charge(total)
// Inside Customer:
function charge(amount):
wallet.deduct(amount)
DTOs y Registros Activos
Los Objetos de Transferencia de Datos (DTOs) son estructuras de datos puras: sin lógica de negocio. Úsalos para mover datos entre capas: respuesta HTTP → servicio, fila de base de datos → dominio. Los Registros Activos añaden save()/find() a los DTOs. La trampa: nunca añadas lógica de negocio a un Registro Activo — crea un objeto de dominio separado para eso.
// ✓ DTO — pure data, no behavior
struct UserDTO:
id
name
email
createdAt
// ✓ Active Record — data + persistence only
class UserRecord:
id
name
email
function save(): ...
function find(id): ...
// ✗ Hybrid — Active Record with business logic (don't do this)
class UserRecord:
...
function canAccessAdmin(): ... // ← business logic here
function calculateSubscriptionPrice(): ... // ← wrong layerDesafío de Código
Rompe el Choque de Trenes — las llamadas encadenadas exponen tres objetos internos. Delega al propietario correcto en cada nivel.
💡Conclusión clave
Los objetos no son mejores que las estructuras de datos — son herramientas diferentes. Elige una y comprométete. Los híbridos te dan lo peor de ambas.
🔧 Algunos ejercicios pueden tener errores. Si algo parece incorrecto, usa el botón Feedback (abajo a la derecha) para reportarlo — nos ayuda a corregirlo rápido.
Pista: Pregunta: ¿quién *posee* cada dato en la cadena? El pedido no debería saber sobre ciudad. Pídele al pedido getShippingCity() y que él delegue internamente — el llamador se mantiene ignorante de la estructura interna.
✗ Tu versión