M4.
Programación con Java
Programa de una tienda departamental
Introducción
La tienda departamental "Dreams" enfrenta desafíos significativos en la gestión de sus operaciones
debido a su crecimiento. Los procesos manuales para el registro de ventas e inventario han
resultado en ineficiencias, errores en los cálculos, pérdidas de stock y dificultades para gestionar
la información de los clientes. Para abordar estos problemas, se requiere un sistema automatizado
en JAVA que optimice la gestión de productos, clientes y ventas. Este documento presenta el
análisis y diseño de un programa orientado a objetos para la tienda "Dreams", con el fin de
proporcionar una solución estructurada y eficiente. El sistema permitirá registrar productos,
administrar clientes y gestionar ventas de manera eficiente, incluyendo la verificación de stock y
el cálculo de totales de venta.
Desarrollo
El desarrollo de este sistema se basa en los principios de la Programación Orientada a Objetos
(POO) para crear una solución robusta y escalable. Se implementarán clases esenciales para
representar las entidades del negocio, sus atributos y los comportamientos necesarios para
gestionar las operaciones de la tienda.
Identificación de Clases y Objetos
El diseño del sistema de la tienda departamental "Dreams" se basa en cuatro clases principales que
representan las entidades clave y la interfaz de usuario de la tienda departamental, cada una con
roles específicos que facilitan la gestión de productos, clientes y ventas.
• Producto: Representa los artículos que están disponibles para la venta en la tienda. Cada
instancia de esta clase será un producto específico (ejemplo: "Laptop", "Monitor", etc.).
• Cliente: Almacena la información de los clientes registrados en la tienda, incluyendo datos
básicos como nombre, correo electrónico, RFC y teléfono. Cada instancia de esta clase será
un cliente individual.
• Venta: Representa una transacción de compra realizada por un cliente. Cada instancia de
esta clase corresponderá a una venta específica, que puede incluir múltiples productos.
• Menu: Actúa como la interfaz de usuario principal del sistema. Es la clase responsable de
mostrar las opciones al usuario, capturar su entrada y coordinar las operaciones entre las
otras clases (Producto, Cliente, Venta).
Definición de Atributos y Métodos
Los atributos y métodos para cada clase:
• Producto:
o Atributos:
▪ nombre: String (Nombre del producto)
▪ precio: double (Precio unitario del producto)
▪ categoria: String (Categoría a la que pertenece el producto)
▪ stock: int (Cantidad disponible del producto en inventario)
o Métodos:
▪ mostrarDetalles(): void (Muestra los detalles del producto)
▪ actualizarStock(int cantidadVendida): void (Reduce el stock del producto
por la cantidad vendida)
▪ getNombre(): String (Obtiene el nombre del producto)
▪ getPrecio(): double (Obtiene el precio del producto)
▪ getCategoria(): String (Obtiene la categoría del producto)
▪ getStock(): int (Obtiene el stock actual del producto)
▪ toString(): String (Devuelve el nombre del producto para su representación
en cadena)
• Cliente:
o Atributos:
▪ nombre: String (Nombre completo del cliente)
▪ correoElectronico: String (Dirección de correo electrónico del cliente)
▪ rfc: String (Registro Federal de Contribuyentes del cliente)
▪ telefono: String (Número de teléfono del cliente)
o Métodos:
▪ getNombre(): String (Obtiene el nombre del cliente)
▪ getCorreoElectronico(): String (Obtiene el correo electrónico del cliente)
▪ getRfc(): String (Obtiene el RFC del cliente)
▪ getTelefono(): String (Obtiene el teléfono del cliente)
▪ obtenerDatosCliente(): void (Muestra los datos completos del cliente)
▪ toString(): String (Devuelve una representación de cadena del cliente, útil
para componentes de interfaz de usuario)
• Venta:
o Atributos:
▪ cliente: Cliente (El cliente asociado a la venta)
▪ productosVendidos: Map<Producto, Integer> (Mapa que almacena los
productos y sus cantidades vendidas en esta venta)
▪ fecha: Date (Fecha en que se realizó la venta)
▪ total: double (Costo total de la venta)
o Métodos:
▪ agregarProducto(Producto producto, int cantidad): void (Añade un
producto a la venta, verificando y actualizando el stock)
▪ calcularTotal(): void (Calcula el monto total de la venta sumando los precios
de los productos vendidos)
▪ registrarVenta(): void (Registra la venta y muestra los detalles, como una
factura)
▪ getCliente(): Cliente (Obtiene el cliente de la venta)
▪ getProductosVendidos(): Map<Producto, Integer> (Obtiene el mapa de
productos vendidos)
▪ getFecha(): Date (Obtiene la fecha de la venta)
▪ getTotal(): double (Obtiene el total de la venta)
• Menu:
o Atributos:
▪ productosDisponibles: List<Producto> (Lista de todos los productos en el
sistema)
▪ clientesRegistrados: List<Cliente> (Lista de todos los clientes en el sistema)
▪ mainPanel: JPanel (Panel principal de la interfaz gráfica)
▪ (Otros JTextFields y JButtons para la interacción de la UI, como
productoNombreCampo, clientNameField, etc.)
o Métodos:
▪ Menu(): Constructor que inicializa el sistema, carga datos iniciales y configura
la interfaz.
▪ iniciarDatos(): void (Método para precargar productos y clientes de ejemplo).
▪ iniciarComponetes(): void (Configura los componentes visuales del menú
principal).
▪ actionPerformed(ActionEvent e): void (Maneja las acciones de los botones del
menú principal).
▪ mostrarRegistroProducto(): void (Muestra el diálogo para registrar un nuevo
producto).
▪ mostrarRegistroCliente(): void (Muestra el diálogo para registrar un nuevo
cliente).
▪ mostrarVentaCliente(): void (Muestra el diálogo para realizar una nueva venta,
incluyendo selección de cliente y productos).
▪ mostrarListaProductos(): void (Muestra la lista de productos disponibles).
▪ mostrarListaClientes(): void (Muestra la lista de clientes registrados).
▪ actualizarListaVentas(DefaultListModel<String> model, Map<Producto,
Integer> productsInSale): void (Método auxiliar para actualizar la lista de
productos en la venta actual).
Relación entre Clases
Las relaciones entre las clases se establecen para reflejar la lógica del negocio de la tienda
departamental:
• Cliente y Venta: Existe una relación de asociación donde un Cliente puede tener múltiples
Ventas. Esto significa que cada instancia de Venta está asociada a una instancia específica
de Cliente.
• Venta y Producto: Hay una relación de agregación donde una Venta puede incluir uno o
varios Productos. La Venta gestiona una colección de Productos (utilizando un
Map<Producto, Integer>), lo que permite registrar la cantidad de cada producto vendido
en una transacción. La vida de los productos no depende de la venta, lo que indica una
agregación.
• Menu y (Producto, Cliente, Venta): La clase Menu tiene relaciones de asociación con
Producto, Cliente y Venta. El Menu contiene y gestiona listas de Productos y Clientes, y
crea instancias de Venta para procesar transacciones. Actúa como el coordinador central
que interactúa con todas las demás clases de dominio.
Diagrama de Clases UML
De acuerdo con los atributos, métodos y las relaciones entre las clases, el diagrama de clases UML
es el siguiente:
Diagrama de objetos
Diagrama de casos de uso
Diagrama de secuencia
Diagrama de actividades
Configuración del Entorno de Desarrollo
Implementación de las Clases
Venta con Cliente: La clase Venta tiene un atributo de tipo Cliente (private Cliente cliente;), lo
que establece una asociación directa donde un cliente puede tener múltiples ventas.
Venta con Producto: La clase Venta utiliza una List<Producto> productos; para almacenar los
productos incluidos en una venta. Esto permite que una venta incluya múltiples productos.
Cuando un producto se agrega a una venta, se pasa el objeto Producto directamente a la lista de
la venta.
Definir las clases necesarias: Producto, Cliente, Venta.
[Link]
public class Producto {
private String nombre;
private double precio;
private String categoria;
private int stock;
public Producto(String nombre, double precio, String categoria, int stock) {
[Link] = nombre;
[Link] = precio;
[Link] = categoria;
[Link] = stock;
}
// Getters
public String getNombre() {
return nombre;
}
public double getPrecio() {
return precio;
}
public String getCategoria() {
return categoria;
}
public int getStock() {
return stock;
}
// Métodos
public void mostrarDetalles() {
[Link]("Producto: " + nombre + " | Precio: $" + precio + " | Categoría: " + categoria + " | Stock: " +
stock);
}
public void actualizarStock(int cantidadVendida) {
if ([Link] >= cantidadVendida) {
[Link] -= cantidadVendida;
// [Link](cantidadVendida + " unidades de " + nombre + " vendidas. Stock actual: " + [Link]);
} else {
// Esto debería ser manejado por la GUI antes de intentar vender
[Link]("No hay suficiente stock de " + nombre + " para vender " + cantidadVendida + " unidades.");
}
}
// --- NUEVO: Sobrescribir el método toString() ---
@Override
public String toString() {
return nombre; // Esto hará que el JComboBox muestre el nombre del producto
}
}
[Link]
public class Cliente {
private String nombre;
private String correoElectronico;
private String rfc; // Nuevo atributo
private String telefono; // Nuevo atributo
public Cliente(String nombre, String correoElectronico, String rfc, String telefono) {
[Link] = nombre;
[Link] = correoElectronico;
[Link] = rfc; // Inicializar RFC
[Link] = telefono; // Inicializar Teléfono
}
// Getters
public String getNombre() {
return nombre;
}
public String getCorreoElectronico() {
return correoElectronico;
}
public String getRfc() { // Nuevo getter
return rfc;
}
public String getTelefono() { // Nuevo getter
return telefono;
}
// Métodos
public void obtenerDatosCliente() {
[Link]("Cliente: " + nombre + " | Correo: " + correoElectronico + " | RFC: " + rfc + " | Teléfono: " +
telefono);
}
@Override
public String toString() { // Es útil para JComboBox y JList
return nombre + " (" + correoElectronico + ")";
}
}
[Link]
//import ...
public class Venta {
private Date fecha;
private Cliente cliente;
private List<Producto> productos; // Usar una lista para múltiples productos
private double total;
public Venta(Cliente cliente) {
[Link] = new Date(); // Fecha actual de la venta
[Link] = cliente;
[Link] = new ArrayList<>(); // Inicializar la lista de productos
[Link] = 0.0;
}
// Getters
public Date getFecha() {
return fecha;
}
public Cliente getCliente() {
return cliente;
}
public List<Producto> getProductos() {
return productos;
}
public double getTotal() {
return total;
}
// Métodos
public void agregarProducto(Producto producto, int cantidad) {
// La validación de stock ahora se hace ANTES de llamar a este método en la GUI.
// Pero esta validación es buena para la coherencia en cualquier punto de llamada.
if ([Link]() >= cantidad) {
for (int i = 0; i < cantidad; i++) {
[Link](producto); // Agregar el producto la cantidad de veces especificada
}
[Link](cantidad); // Actualizar el stock del producto
calcularTotal(); // Recalcular el total después de agregar el producto
// [Link](cantidad + " unidades de " + [Link]() + " agregadas a la venta."); // Esta lí-
nea ahora podría ser un JOptionPane
} else {
// Esto debería ser manejado por la GUI antes de llegar aquí,
// pero se mantiene como una salvaguarda.
[Link]("No hay suficiente stock de " + [Link]() + ". Stock actual: " +
[Link]());
}
}
public double calcularTotal() {
[Link] = 0.0;
for (Producto p : productos) {
[Link] += [Link](); // Sumar el precio de cada producto en la lista
}
return [Link];
}
public void registrarVenta() {
[Link]("\n--- DETALLES DE LA VENTA ---");
[Link]("Fecha: " + fecha);
[Link]("Cliente: ");
[Link](); // Mostrar datos del cliente
[Link]("Productos vendidos:");
[Link]()
.collect([Link](Producto::getNombre, [Link]()))
.forEach((nombre, count) -> [Link]("- " + nombre + " (x" + count + ")"));
[Link]("Total de la venta: $" + [Link]("%.2f", total));
[Link]("----------------------------\n");
}
Aplicación de Relaciones Entre Clases
//import ...
public class Menu extends JFrame implements ActionListener {
private List<Producto> productosDisponibles;
private List<Cliente> clientesRegistrados;
private JPanel mainPanel;
private JTextField productoNombreCampo;
private JTextField productPriceField;
private JTextField productCategoryField;
private JTextField productStockField;
private JTextField clienteNombreCampo;
private JTextField clienteCorreoCampo;
private JTextField clienteRfcCampo;
private JTextField clienteTelefonoCampo;
public Menu() {
super("Tienda Dreams - Gestión Departamental");
[Link] = new ArrayList<>();
[Link] = new ArrayList<>();
iniciarDatos();
setSize(500, 400);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
iniciarComponetes();
setVisible(true);
}
private void iniciarDatos() {
[Link](new Producto("Laptop", 1200.00, "Computadoras", 6));
[Link](new Producto("Monitor", 350.00, "Computadoras", 5));
[Link](new Producto("Teclado", 80.00, "Computadoras", 7));
[Link](new Producto("Mouse", 30.00, "Computadoras", 12));
[Link](new Producto("SSD", 150.00, "Computadoras", 8));
[Link](new Cliente("Ana García", "[Link]@[Link]", "GARCIA800101ABC", "5511223344"));
[Link](new Cliente("Luis Fernández", "luis.f@[Link]", "FERNAN790202DEF", "5522334455"));
[Link](new Cliente("María López", "[Link]@[Link]", "LOPEZ810303GHI", "5533445566"));
[Link](new Cliente("Carlos Ruiz", "carlos.r@[Link]", "RUIZ820404JKL", "5544556677"));
[Link](new Cliente("Sofía Martínez", "sofia.m@[Link]", "MARTI830505MNO", "5555667788"));
[Link](new Cliente("Pedro Sánchez", "pedro.s@[Link]", "SANCH840606PQR", "5566778899"));
[Link](new Cliente("Laura Gómez", "laura.g@[Link]", "GOMEZ850707STU", "5577889900"));
[Link](new Cliente("Diego Pérez", "diego.p@[Link]", "PEREZ860808VWX", "5588990011"));
[Link](new Cliente("Elena Díaz", "elena.d@[Link]", "DIAZ870909YZA", "5599001122"));
[Link](new Cliente("Pablo Torres", "pablo.t@[Link]", "TORRE881010BCD", "5500112233"));
[Link]("Datos iniciales cargados: 5 productos de computadora y 10 clientes.");
}
private void iniciarComponetes() {
mainPanel = new JPanel();
[Link](new GridLayout(6, 1, 10, 10));
[Link]([Link](20, 20, 20, 20));
JButton registerProductButton = new JButton("1. Registrar Producto");
JButton registerClientButton = new JButton("2. Registrar Cliente");
JButton sellProductButton = new JButton("3. Realizar Venta");
JButton showProductsButton = new JButton("4. Mostrar Productos Disponibles");
JButton showClientsButton = new JButton("5. Mostrar Clientes Registrados");
JButton exitButton = new JButton("0. Salir");
[Link](this);
[Link](this);
[Link](this);
[Link](this);
[Link](this);
[Link](this);
[Link](registerProductButton);
[Link](registerClientButton);
[Link](sellProductButton);
[Link](showProductsButton);
[Link](showClientsButton);
[Link](exitButton);
add(mainPanel);
}
@Override
public void actionPerformed(ActionEvent e) {
String command = [Link]();
switch (command) {
case "1. Registrar Producto":
mostrarRegistroProducto();
break;
case "2. Registrar Cliente":
mostrarRegistroCliente();
break;
case "3. Realizar Venta":
mostrarVentaCliente();
break;
case "4. Mostrar Productos Disponibles":
mostrarListaProductos();
break;
case "5. Mostrar Clientes Registrados":
mostrarListaClientes();
break;
case "0. Salir":
[Link](0);
break;
}
}
private void mostrarRegistroProducto() {
JPanel productFormPanel = new JPanel(new GridLayout(5, 2, 10, 5));
[Link](new JLabel("Nombre:"));
productoNombreCampo = new JTextField();
[Link](productoNombreCampo);
[Link](new JLabel("Precio:"));
productPriceField = new JTextField();
[Link](productPriceField);
[Link](new JLabel("Categoría:"));
productCategoryField = new JTextField();
[Link](productCategoryField);
[Link](new JLabel("Stock:"));
productStockField = new JTextField();
[Link](productStockField);
int result = [Link](this, productFormPanel, "Registrar Nuevo Producto",
JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE);
if (result == JOptionPane.OK_OPTION) {
try {
String nombre = [Link]();
double precio = [Link]([Link]());
String categoria = [Link]();
int stock = [Link]([Link]());
if ([Link]() || [Link]()) {
[Link](this, "Nombre y Categoría no pueden estar vacíos.", "Error de Entrada",
JOptionPane.ERROR_MESSAGE);
return;
}
Producto nuevoProducto = new Producto(nombre, precio, categoria, stock);
[Link](nuevoProducto);
[Link](this, "Producto '" + nombre + "' registrado con éxito.", "Registro Exitoso",
JOptionPane.INFORMATION_MESSAGE);
} catch (NumberFormatException ex) {
[Link](this, "Por favor, ingrese valores numéricos válidos para Precio y Stock.",
"Error de Formato", JOptionPane.ERROR_MESSAGE);
}
}
}
private void mostrarRegistroCliente() {
JPanel clienteFormPanel = new JPanel(new GridLayout(5, 2, 10, 5));
[Link](new JLabel("Nombre:"));
clienteNombreCampo = new JTextField();
[Link](clienteNombreCampo);
[Link](new JLabel("Correo Electrónico:"));
clienteCorreoCampo = new JTextField();
[Link](clienteCorreoCampo);
[Link](new JLabel("RFC:"));
clienteRfcCampo = new JTextField();
[Link](clienteRfcCampo);
[Link](new JLabel("Teléfono:"));
clienteTelefonoCampo = new JTextField();
[Link](clienteTelefonoCampo);
int result = [Link](this, clienteFormPanel, "Registrar Nuevo Cliente",
JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE);
if (result == JOptionPane.OK_OPTION) {
String nombre = [Link]();
String email = [Link]();
String rfc = [Link]();
String telefono = [Link]();
if ([Link]() || [Link]() || [Link]() || [Link]()) {
[Link](this, "Todos los campos del cliente son obligatorios.", "Error de Entrada",
JOptionPane.ERROR_MESSAGE);
return;
}
Cliente nuevoCliente = new Cliente(nombre, email, rfc, telefono);
[Link](nuevoCliente);
[Link](this, "Cliente '" + nombre + "' registrado con éxito.", "Registro Exitoso", JOpti-
onPane.INFORMATION_MESSAGE);
}
}
private void mostrarListaProductos() {
if ([Link]()) {
[Link](this, "No hay productos registrados.", "Productos", JOptionPane.INFORMATION_MES-
SAGE);
return;
}
StringBuilder sb = new StringBuilder("--- PRODUCTOS DISPONIBLES ---\n");
for (Producto p : productosDisponibles) {
[Link]("Nombre: ").append([Link]())
.append(" | Precio: $").append([Link]("%.2f", [Link]()))
.append(" | Categoría: ").append([Link]())
.append(" | Stock: ").append([Link]()).append("\n");
}
[Link](this, [Link](), "Lista de Productos", JOptionPane.PLAIN_MESSAGE);
}
private void mostrarListaClientes() {
if ([Link]()) {
[Link](this, "No hay clientes registrados.", "Clientes", JOptionPane.INFORMATION_MESSAGE);
return;
}
StringBuilder sb = new StringBuilder("--- CLIENTES REGISTRADOS ---\n");
for (Cliente c : clientesRegistrados) {
[Link]("Nombre: ").append([Link]())
.append(" | Correo: ").append([Link]())
.append(" | RFC: ").append([Link]())
.append(" | Teléfono: ").append([Link]()).append("\n");
}
[Link](this, [Link](), "Lista de Clientes", JOptionPane.PLAIN_MESSAGE);
}
private void mostrarVentaCliente() {
if ([Link]()) {
[Link](this, "No hay clientes registrados. Por favor, registre un cliente primero.",
"Error de Venta", JOptionPane.WARNING_MESSAGE);
return;
}
if ([Link]()) {
[Link](this, "No hay productos disponibles para la venta. Por favor, registre productos
primero.", "Error de Venta", JOptionPane.WARNING_MESSAGE);
return;
}
JPanel sellPanel = new JPanel(new BorderLayout(10, 10));
JPanel clientSelectionPanel = new JPanel(new FlowLayout([Link]));
[Link](new JLabel("Seleccione Cliente:"));
JComboBox<Cliente> clientComboBox = new JComboBox<>([Link](new Cliente[0]));
[Link](clientComboBox);
[Link](clientSelectionPanel, [Link]);
JPanel productAddSection = new JPanel(new BorderLayout());
[Link]([Link]("Añadir Productos a la Venta"));
// --- CAMBIO CLAVE AQUÍ: Usar GridLayout para productInputPanel ---
JPanel productInputPanel = new JPanel(new GridLayout(2, 4, 5, 5)); // 2 filas, 4 columnas, espaciado
JComboBox<Producto> productComboBox = new JComboBox<>([Link](new Producto[0]));
JTextField quantityField = new JTextField(5);
JButton addProductToSaleButton = new JButton("Añadir");
JLabel stockInfoLabel = new JLabel("Stock: ");
// Primera fila: Producto y Stock
[Link](new JLabel("Producto:"));
[Link](productComboBox);
[Link](stockInfoLabel); // El stock va después del combobox
[Link](new JLabel("")); // Espacio en blanco para alinear el botón 'Añadir' en la segunda fila
// Segunda fila: Cantidad y botón Añadir
[Link](new JLabel("Cantidad:"));
[Link](quantityField);
[Link](new JLabel("")); // Espacio en blanco
[Link](addProductToSaleButton); // El botón Añadir
[Link](productInputPanel, [Link]);
[Link](new ItemListener() {
@Override
public void itemStateChanged(ItemEvent e) {
if ([Link]() == [Link]) {
Producto selectedProduct = (Producto) [Link]();
[Link]("Stock: " + [Link]());
}
}
});
// Inicializar el stockInfoLabel con el stock del primer producto seleccionado (si existe)
if ([Link]() > 0) {
Producto initialProduct = (Producto) [Link]();
[Link]("Stock: " + [Link]());
}
DefaultListModel<String> currentSaleListModel = new DefaultListModel<>();
JList<String> currentSaleList = new JList<>(currentSaleListModel);
JScrollPane scrollPane = new JScrollPane(currentSaleList);
[Link](scrollPane, [Link]);
Map<Producto, Integer> productosParaVenta = new HashMap<>();
[Link](new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
Producto selectedProduct = (Producto) [Link]();
if (selectedProduct == null) {
[Link](sellPanel, "Por favor, seleccione un producto.", "Error", JOpti-
onPane.ERROR_MESSAGE);
return;
}
try {
int quantity = [Link]([Link]());
if (quantity <= 0) {
[Link](sellPanel, "La cantidad debe ser mayor a 0.", "Error", JOpti-
onPane.ERROR_MESSAGE);
return;
}
if ([Link]() < quantity) {
[Link](sellPanel, "No hay suficiente stock de " + [Link]()
+ " (Stock actual: " + [Link]() + ").", "Stock Insuficiente", JOptionPane.WARNING_MESSAGE);
return;
}
[Link](selectedProduct, [Link](selectedProduct, 0) + quantity);
actualizarListaVentas(currentSaleListModel, productosParaVenta);
// Actualizar el stock mostrado después de añadir el producto a la venta
[Link]("Stock: " + [Link]());
[Link]("");
[Link](sellPanel, quantity + " unidades de " + [Link]() + "
añadidas temporalmente.", "Producto Añadido", JOptionPane.INFORMATION_MESSAGE);
} catch (NumberFormatException ex) {
[Link](sellPanel, "Por favor, ingrese una cantidad numérica válida.", "Error de
Formato", JOptionPane.ERROR_MESSAGE);
}
}
});
[Link](productAddSection, [Link]);
JButton registerSaleButton = new JButton("Registrar Venta Final");
[Link](new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
Cliente selectedClient = (Cliente) [Link]();
if (selectedClient == null) {
[Link](sellPanel, "Debe seleccionar un cliente para la venta.", "Error de Venta",
JOptionPane.ERROR_MESSAGE);
return;
}
if ([Link]()) {
[Link](sellPanel, "Debe añadir al menos un producto a la venta.", "Error de
Venta", JOptionPane.ERROR_MESSAGE);
return;
}
Venta nuevaVenta = new Venta(selectedClient);
boolean ventaExitosa = true;
for ([Link]<Producto, Integer> entry : [Link]()) {
Producto prod = [Link]();
int qty = [Link]();
if ([Link]() < qty) {
[Link](sellPanel, "Error: Stock insuficiente para " + [Link]() + ".
Venta cancelada.", "Error de Stock", JOptionPane.ERROR_MESSAGE);
ventaExitosa = false;
break;
}
[Link](prod, qty); // This method already updates the product stock [cite: 9]
}
if (ventaExitosa) {
[Link](); // Calculate the total of a sale based on product prices [cite: 10]
[Link](); // Register sales, indicating product sold, quantity, and assigning purchase
to registered customers. [cite: 9]
[Link](sellPanel, "Venta registrada con éxito!\nTotal: $" + [Link]("%.2f",
[Link]()) + "\nRevisa la consola para los detalles.", "Venta Exitosa", JOptionPane.INFORMATION_MESSAGE);
[Link](sellPanel).dispose();
}
}
});
[Link](registerSaleButton, [Link]);
[Link](this, sellPanel, "Realizar Nueva Venta",
JOptionPane.DEFAULT_OPTION, JOptionPane.PLAIN_MESSAGE, null, new Object[]{}, null);
}
private void actualizarListaVentas(DefaultListModel<String> model, Map<Producto, Integer> productsInSale) {
[Link]();
for ([Link]<Producto, Integer> entry : [Link]()) {
[Link]([Link]().getNombre() + " (x" + [Link]() + ")");
}
}
}
Implementación del Flujo del Programa en Main
El flujo del programa se gestiona principalmente a través de la clase Menu. La clase TiendaApp
(que contiene el método main) simplemente crea una instancia de Menu y llama a su método
mostrarMenu() para iniciar la interacción con el usuario. Desde el Menu, el usuario puede:
Crear instancias de productos y clientes a través de las opciones "Registrar Producto" y "Registrar
Cliente".
Simular el proceso de compra agregando productos a una venta a través de la opción "Realizar
Venta".
//import ...
public class TiendaApp {
public static void main(String[] args) {
[Link](() -> {
new Menu();
});
}
}
Reflexión
Describe la función de cada clase (Producto, Cliente, Venta, Menu) y explica cómo interactúan
entre sí.
Producto: Representa un artículo disponible en la tienda. Su función es encapsular la información
básica de un producto (nombre, precio, categoría, stock) y proporcionar métodos para mostrar sus
detalles y actualizar su stock.
Cliente: Representa a un cliente de la tienda. Su función es almacenar los datos básicos del cliente
(nombre, correo electrónico) y permitir la visualización de estos datos.
Venta: Representa una transacción de compra. Su función es registrar la fecha, el cliente asociado,
y la lista de productos comprados, además de calcular el total de la venta y mostrar los detalles.
Interactúa con Producto para verificar el stock y actualizarlo, y con Cliente para asociar la venta
a un cliente específico.
Menu: Es la interfaz principal para el usuario. Su función es mostrar las opciones disponibles
(registrar productos, registrar clientes, realizar ventas, mostrar listados) y orquestar las
interacciones entre las demás clases. Menu crea y gestiona instancias de Producto y Cliente, y
coordina la creación de Ventas, pasando los objetos Producto y Cliente necesarios.
¿Cómo se aplican los principios de POO (encapsulamiento, herencia, polimorfismo, abstracción)
en este sistema? Proporciona ejemplos concretos del código.
Encapsulamiento: Se aplica al declarar los atributos de las clases (Producto, Cliente, Venta) como
private. Se proporcionan métodos public (getters y setters, como getNombre(), setStock()) para
acceder y modificar estos atributos de manera controlada. Por ejemplo, en Producto, stock es
private y solo se puede modificar a través de setStock() o actualizarStock(), lo que permite validar
que el stock no sea negativo.
Abstracción: Cada clase es una abstracción de una entidad del mundo real. Por ejemplo, la clase
Producto abstrae las características esenciales de cualquier artículo en venta (nombre, precio,
stock), ocultando los detalles de su implementación interna. El usuario del sistema interactúa con
el Menu sin necesidad de conocer cómo se gestionan internamente las listas de productos o
clientes.
Herencia y Polimorfismo: En este diseño básico, no se han implementado explícitamente herencia
ni polimorfismo. Sin embargo, se podrían añadir fácilmente. Por ejemplo, se podría tener una
clase base Producto y clases derivadas como ProductoElectronico o ProductoRopa que hereden
de Producto y añadan atributos específicos. El polimorfismo podría usarse si un método
procesarVenta() pudiera aceptar diferentes tipos de Productos derivados.
¿Las clases implementadas en Java corresponden a las que se planificaron en el análisis y diseño?
Si hubo cambios, ¿Cuáles fueron y por qué?
Sí, las clases implementadas (Producto, Cliente, Venta, Menu) corresponden directamente a las
planificadas en el análisis y diseño. La clase Menu fue añadida en la fase de diseño para gestionar
la interacción del usuario, y se ha implementado con las funcionalidades esperadas (registro de
productos y clientes, y orquestación de la venta). Pero hubo algunos cambios en la estructura de
las clases principales respecto al diseño, estos cambios eran necesarios para mejorar el
funcionamiento del sistema.
Explica cómo aplicarías el principio de encapsulamiento en las clases Producto y Venta, y por qué
sería importante.
Producto: En la clase Producto, los atributos nombre, precio, categoria, y stock están declarados
como private. Esto significa que no se pueden acceder directamente desde fuera de la clase. Para
interactuar con ellos, se usan métodos public como getNombre(), getPrecio(), getCategoria(),
getStock(), y setStock(). La importancia en el encapsulamiento es crucial aquí porque protege la
integridad de los datos. Por ejemplo, el método setStock() puede incluir lógica para asegurar que
el stock nunca sea un valor negativo (if (stock >= 0)), evitando estados inconsistentes del objeto.
También permite cambiar la implementación interna de cómo se almacenan los datos sin afectar
el código que usa la clase Producto.
Venta: De manera similar, los atributos fecha, cliente, productos, y total en la clase Venta son
private. Se accede a ellos a través de getFecha(), getCliente(), getProductos(), y getTotal(). La
importancia en el encapsulamiento garantiza que la lógica de la venta (como el cálculo del total)
se maneje internamente por la clase Venta (calcularTotal()). El acceso directo a la lista de
productos o al total podría llevar a cálculos incorrectos si se modificaran externamente sin usar
los métodos provistos por la clase Venta, lo que podría resultar en "errores en los cálculos".
Explica cómo Venta gestiona los productos en su lista. ¿Esta relación representa agregación o
composición? Justifica tu respuesta con el código.
La clase Venta gestiona los productos a través de una List<Producto> llamada productos. Esto se
observa en el constructor de Venta:
public Venta(Cliente cliente) {
// ...
[Link] = new ArrayList<>(); // Inicializar la lista de productos
// ...
}
Y en el método agregarProducto:
public void agregarProducto(Producto producto, int cantidad) {
// ...
[Link](producto); // Agregar el producto a la lista
// ...
}
Esta relación representa agregación.
Justificación con el código:
En este código, los objetos Producto pueden existir independientemente de los objetos Venta.
Cuando se crea un Producto (por ejemplo, en el método registrarProducto del Menu), se añade a
una lista global de productos disponibles (productosDisponibles en la clase Menu). Luego, cuando
se realiza una venta y se agrega un Producto a la List<Producto> de la Venta, se está añadiendo
una referencia a un objeto Producto ya existente, no creando una nueva instancia de Producto
que dependa exclusivamente de esa Venta.
Si la Venta se destruyera (se elimina), los Productos individuales que formaron parte de esa venta
seguirían existiendo y podrían estar disponibles en el inventario o ser parte de otras ventas. Esto
es la característica definitoria de la agregación: las partes (los Productos) pueden existir
independientemente del todo (la Venta).
Para que fuera composición, la vida útil de los Productos en la lista de Venta tendría que estar
ligada estrictamente a la vida útil de la Venta (es decir, si la Venta se destruye, los Productos
asociados a ella también lo harían o no existirían sin ella), lo cual no es el caso aquí, ya que los
Productos son entidades persistentes en el inventario de la tienda.
Conclusión
Este análisis y diseño proporciona una base sólida para el desarrollo de un sistema de gestión para
la tienda departamental "Dreams". La aplicación de los principios de la Programación Orientada
a Objetos permite modelar las entidades y procesos del negocio de manera efectiva, facilitando la
creación de un sistema automatizado que mejore la eficiencia operativa, reduzca los errores y
proporcione una mejor gestión de la información. La implementación de este sistema contribuirá
significativamente a la modernización de la tienda "Dreams", permitiéndole adaptarse al
crecimiento y ofrecer un mejor servicio a sus clientes.