domain - PowerSystem2024/CapybaraFilms_ProyectoTercerSemestre GitHub Wiki
La Capa de Dominio constituye el corazón del sistema Capybara Films, encapsulando la lógica de negocio fundamental y las reglas que gobiernan las operaciones de reserva de cine. Esta capa implementa los principios de Domain-Driven Design (DDD), manteniendo la independencia de la infraestructura y enfocándose exclusivamente en los conceptos del negocio.
La capa de dominio tiene como objetivo principal modelar los conceptos del mundo real del negocio cinematográfico en código, proporcionando:
-
Entidades de Negocio: Representan los objetos principales del dominio como
Cliente.py
,Reserva.py
,Butaca.py
,Pelicula.py
,Sala.py
yCandy.py
. -
Reglas de Negocio: Implementa validaciones y lógica específica del dominio directamente en las entidades, como las validaciones de DNI en
Cliente.py:37-40
y el cálculo de precios enReserva.py:28-55
. -
Tipos de Dominio: Define enumeraciones y value objects que garantizan consistencia y type safety, incluyendo
TipoButaca.py
,TipoCandy.py
,FormatoPelicula.py
yUbicacion.py
.
El diseño sigue patrones establecidos de DDD:
-
Aggregate Root: La entidad
Reserva
actúa como agregado raíz, coordinando todas las operaciones relacionadas con una reserva de cine. -
Value Objects:
Ubicacion
proporciona inmutabilidad para las posiciones de butacas. - Domain Services: La lógica de negocio está distribuida entre las entidades apropiadas.
-
Enumerations: Los tipos como
TipoButaca
yTipoCandy
encapsulan tanto valores como comportamiento relacionado.
graph TD
subgraph Capa de Dominio
subgraph Entidades Principales
Reserva --> Cliente
Reserva --> Butaca
Reserva --> Sala
Reserva --> Candy
Pelicula
end
subgraph Tipos de Dominio
Butaca --> TipoButaca
Butaca --> Ubicacion
Candy --> TipoCandy
Pelicula --> FormatoPelicula
end
end
Esta capa se integra de manera limpia con las otras capas del sistema:
-
Servicios:
cine_services.py
orquesta las operaciones utilizando las entidades de dominio - Acceso a Datos: Los DAOs persisten y recuperan las entidades manteniendo su integridad
-
Presentación:
main.py
coordina el flujo de usuario a través de las capas superiores
La separación clara de responsabilidades permite que la lógica de negocio permanezca estable e independiente de cambios en la infraestructura o la presentación, facilitando el mantenimiento y la evolución del sistema.
La entidad Cliente
representa a los usuarios del sistema de cine con validaciones integradas para garantizar la integridad de los datos.
- Almacenar información personal del cliente (DNI, nombre, apellido, email).
- Validar datos de entrada según reglas de negocio.
- Proporcionar acceso controlado a los atributos mediante getters/setters.
- Servir como identificador único para las reservas.
Atributo | Tipo | Propósito | Validación |
---|---|---|---|
id_cliente |
int | Identificador único en BD | Asignado automáticamente |
dni |
str | Documento de identidad | Solo números, 8 dígitos |
nombre |
str | Nombre del cliente | No vacío, solo letras y espacios |
apellido |
str | Apellido del cliente | No vacío, solo letras y espacios |
email |
str | Correo electrónico | Debe contener '@' y '.' |
cliente = Cliente()
try:
cliente.set_dni("12345678") # Válido
cliente.set_dni("1234567a") # Lanza ValueError
except ValueError as e:
print(f"Error: {e}")
try:
cliente.set_nombre("Juan Carlos") # Válido
cliente.set_nombre("") # Lanza ValueError
except ValueError as e:
print(f"Error: {e}")
falta esto
La entidad Cliente
implementa validación defensiva mediante excepciones ValueError
:
- DNI inválido: "El DNI debe contener solo números"
- Nombre/Apellido vacío: "El nombre/apellido no puede estar vacío"
- Email inválido: "El email no es válido"
classDiagram
ServicioValidacion : +es_nombre_valido()
class Cliente {
- dni: str
- nombre: str
- apellido: str
- email: str
}
class Reserva {
- cliente: Cliente
}
class ClienteDAO {
+buscar_por_dni()
}
ServicioValidacion --> Cliente
Cliente "1" --o "1" Reserva : cliente
Cliente --> ClienteDAO
- Con Reserva: Un cliente puede tener múltiples reservas.
- Con ClienteDAO: Persistencia y recuperación de datos.
- Con ServicioValidacion: Validación adicional de nombres.
La entidad Reserva
actúa como agregado raíz del dominio, orquestando una transacción completa de reserva de cine.
- Coordinar todos los componentes de una reserva (cliente, sala, butacas, combos)
- Calcular el precio total de la reserva
- Generar resúmenes detallados para el cliente
- Gestionar la fecha/hora de la reserva
- Mantener la integridad del agregado
Atributo | Tipo | Propósito | Valor por Defecto |
---|---|---|---|
id_reserva |
str | Identificador único | Asignado por BD |
cliente |
Cliente | Cliente que reserva | Requerido |
sala |
Sala | Sala de cine | Requerido |
candy |
list[Candy] | Combos seleccionados | Lista vacía |
butacas_asignadas |
list[Butaca] | Butacas reservadas | Lista vacía |
fecha_hora |
datetime | Timestamp de reserva | datetime.now() |
reserva = Reserva(cliente, sala, candy=[combo1, combo2], butacas_asignadas=[butaca1, butaca2])
precio_total = reserva.calcular_precio_total()
print(f"Total a pagar: ${precio_total}")
reserva.mostrar_resumen()
# Imprime resumen detallado con:
# - Información del cliente
# - Butacas reservadas con precios
# - Combos seleccionados
# - Total a pagar
La entidad Reserva
implementa manejo robusto de errores:
- Captura errores al obtener categoría de butacas
- Maneja errores al acceder a precios de combos
- Continúa el cálculo aunque falle un elemento individual
- Captura errores generales durante la presentación
- Proporciona mensajes de error descriptivos
graph TD
ReservaDAO --> Reserva
CineServices --> Reserva
subgraph Reserva - Aggregate Root
Reserva["Reserva - Aggregate Root
- calcular_precio_total
- mostrar_resumen"]
end
Reserva --> Cliente["Cliente
- nombre, apellido, email"]
Reserva --> Sala["Sala
- id_sala"]
Reserva --> Butaca["Butaca
- categoria, fila, columna"]
Reserva --> Candy["Candy
- tipo, precio"]
Butaca --> TipoButaca
Candy --> TipoCandy
- Agregado raíz: Controla acceso a entidades relacionadas
- Con TipoButaca: Utiliza enum para cálculo de precios
- Con CineServices: Integración para obtener precios por categoría
- Con ReservaDAO: Persistencia del agregado completo
-
Reserva
controla el acceso a todas las entidades relacionadas - Mantiene la consistencia del dominio
- Coordina operaciones complejas entre múltiples entidades
- Utiliza
CineServices.obtener_precio_por_categoria()
para cálculos - Delega validaciones específicas a servicios apropiados
La entidad Reserva
demuestra cómo un agregado raíz puede coordinar múltiples entidades mientras mantiene la integridad del dominio y proporciona una interfaz cohesiva para operaciones complejas de negocio.
La entidad Butaca
representa asientos individuales de cine con seguimiento de ubicación y gestión de disponibilidad.
- Gestionar el estado de disponibilidad de cada asiento (ocupado/libre).
- Mantener información de ubicación física (fila y columna).
- Categorizar asientos por tipo (común o premium).
- Proporcionar métodos para cambio de estado controlado.
Atributo | Tipo | Propósito | Validación |
---|---|---|---|
id_butaca |
int | Identificador único | Asignado por BD |
fila |
int | Número de fila (1-12) | Rango válido |
columna |
int | Número de columna (1-12) | Rango válido |
categoria |
str | Tipo de butaca (común/premium) | Valores predefinidos |
estado |
bool | Disponibilidad (True=ocupada, False=libre) | Booleano |
butaca = Butaca(1, 5, 3, "premium", False)
butaca.set_estado(True) # Marcar como ocupada
print(butaca.is_estado()) # True - está ocupada
Fuente: Butaca.py:9-11
fila = butaca.get_fila() # Obtiene número de fila
columna = butaca.get_columna() # Obtiene número de columna
categoria = butaca.get_categoria() # Obtiene tipo de butaca
Fuente: Butaca.py:30-34
def __str__(self): # texto a imprimir de la butaca seleccionada por el cliente
return f"Categoria: {self.categoria}, Ubicacion: {self.ubicacion}, Estado: {'Ocupada' if self.estado else 'Libre'}"
Fuente: Butaca.py:36-37
La entidad Butaca
implementa validación básica:
- Los métodos getter/setter proporcionan acceso controlado.
- La representación textual maneja estados booleanos de forma legible.
- No implementa validaciones complejas, delegando esto a la capa de servicios.
graph TD
Reserva --> ButacaNode
ButacaDAO --> ButacaNode
CineServices --> ButacaNode
subgraph ButacaSubgraph
ButacaNode["Butaca
- fila: int
- columna: int
- categoria: str
- estado: bool"]
end
ButacaNode --> TipoButaca["TipoButaca
COMUN/PREMIUM"]
ButacaNode --> Ubicacion["Ubicacion
Value Object"]
- Con TipoButaca: Determina precios según categoría.
- Con Ubicacion: Value object para posicionamiento.
- Con Reserva: Múltiples butacas por reserva.
- Con ButacaDAO: Persistencia y consultas de disponibilidad.
- Con CineServices: Visualización de matriz y selección.
La entidad Pelicula
encapsula toda la información relacionada con las películas disponibles en el sistema de cine.
- Almacenar información completa de películas (título, director, duración, etc.)
- Gestionar formatos de proyección (2D/3D)
- Proporcionar métodos de acceso y modificación controlados
- Convertir formatos de string a enumeraciones
Atributo | Tipo | Propósito | Validación |
---|---|---|---|
id_pelicula |
int | Identificador único | Asignado por BD |
nombre |
str | Título de la película | Requerido |
director |
str | Director de la película | Requerido |
duracion |
int | Duración en minutos | Número positivo |
genero |
str | Género cinematográfico | Texto libre |
idioma |
str | Idioma de la película | Texto libre |
formato |
FormatoPelicula | Formato de proyección | Enum 2D/3D |
pelicula = Pelicula(1, "Avatar", "James Cameron", 180, "Sci-Fi", "Inglés", "3D")
formato_enum = pelicula.convertir_formato("3D") # Convierte string a enum
Fuente: Pelicula.py:13-18
pelicula.set_nombre("Avatar: El Camino del Agua")
pelicula.set_duracion(192)
print(f"Película: {pelicula.get_nombre()}, Duración: {pelicula.get_duracion()} min")
Fuente: Pelicula.py:20-25
def get_formato(self) -> FormatoPelicula:
"""Devuelve el formato de la película."""
return self.formato
def set_formato(self, formato: FormatoPelicula):
"""Establece un nuevo formato a la película."""
self.formato = formato
Fuente: Pelicula.py:59-65
La entidad Pelicula
implementa manejo de errores específico:
-
Formato inválido: Lanza
ValueError
si el formato no existe en el enum. - Validación de tipos: Los setters incluyen type hints para validación.
-
Conversión segura: El método
convertir_formato()
valida antes de convertir.
graph TD
Sala --> PeliculaNode
PeliculaDAO --> PeliculaNode
CineServices --> PeliculaNode
subgraph PeliculaSubgraph
PeliculaNode["Pelicula
- nombre: str
- director: str
- duracion: int
- formato: FormatoPelicula"]
end
PeliculaNode --> FormatoPelicula["FormatoPelicula DOS_D/TRES_D"]
- Con FormatoPelicula: Enum para formatos de proyección con precios adicionales
- Con Sala: Asociación película-sala para proyecciones
- Con PeliculaDAO: Persistencia y consultas del catálogo
- Con CineServices: Selección de películas en el flujo de reserva
La representación __str__
proporciona una vista completa de todos los atributos de la película, útil para debugging y logging del sistema.
Encapsulación: Todos los atributos tienen métodos getter/setter dedicados. Type Safety: Integración con enums para garantizar valores válidos. Domain Validation: Validación de formatos en el nivel de dominio.
Ambas entidades (Butaca
y Pelicula
) demuestran principios sólidos de diseño de dominio, manteniendo la lógica de negocio encapsulada y proporcionando interfaces claras para su uso en las capas superiores del sistema.