Ejemplos

Ejemplo 5: Sistema de Gestión de Empleados

Implementación de un sistema de gestión de empleados utilizando validación de datos con JOptionPane.

Conceptos clave

  • Herencia: Permite que una clase (hija) herede atributos y métodos de otra clase (padre). Así podemos reutilizar código y establecer relaciones "es-un".
  • Sobrecarga: Consiste en definir varios métodos con el mismo nombre pero diferentes parámetros (tipo, número o ambos). Se resuelve en tiempo de compilación.

Descripción del problema

Tenemos dos tipos principales de empleados:

  • Empleado a tiempo completo: Tiene un salario mensual fijo.
  • Empleado por horas: Se le paga según las horas trabajadas y una tarifa por hora.

Ambos comparten datos básicos: nombre, ID y departamento. Además, necesitamos calcular su pago, pero de forma distinta. También queremos flexibilidad para calcular pagos considerando horas extra o bonos.

Así mismo deberá de contar con un menú de interacción para agregar empleados, mostrar su información y calcular su pago, además de validar los datos ingresados por el usuario utilizando JOptionPane.

Implementación

Clase base Emplployee

package app.empresa;

public abstract class Employee {

    private static int ID = 1;
    protected final int idEmployee;
    protected String name;
    protected Department department;

    public Employee(String name, Department department) {
        this.idEmployee = ID++;
        this.name = name;
        this.department = department;
    }

    public abstract double getSalary();

    public int getIdEmployee() {
        return idEmployee;
    }

    public String getName() {
        return name;
    }

    public Department getDepartment() {
        return department;
    }

    public void setDepartment(Department department) {
        this.department = department;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return String.format("ID: %d, Nombre: %s", idEmployee, name);
    }
}

Clase FullTimeEmployee

package app.empresa;

import java.util.Arrays;
import java.util.stream.IntStream;

public class FullTimeEmployee extends Employee {

    private final double salary;
    private final double[] benefits;

    public FullTimeEmployee(String name, Department department, double salary) {
        super(name, department);
        this.salary = salary;
        this.benefits = new double[5];
    }

    public void addBenefit(double benefit) {

        IntStream.range(0, benefits.length).filter(i -> benefits[i] == 0).findFirst().ifPresent(i -> benefits[i] = benefit);
    }

    public void deleteBenefit(double benefit) {

        IntStream.range(0, benefits.length).filter(i -> benefits[i] == benefit).findFirst().ifPresent(i -> benefits[i] = 0);
    }

    @Override
    public double getSalary() {

        double finalSalary = salary;
        finalSalary += Arrays.stream(benefits).sum();
        return finalSalary;
    }

    public boolean isBenefitsFull() {
        return Arrays.stream(benefits).allMatch(b -> b > 0);
    }

    public boolean hasBenefits() {
        return Arrays.stream(benefits).anyMatch(b -> b > 0);
    }

    public Double[] getBenefits() {
        return Arrays.stream(benefits).boxed().toArray(Double[]::new);
    }
}

Clase HourlyEmployee

package app.empresa;

public class HourlyEmployee extends Employee {

    private final double hourlyRate;
    private int extraHours;
    private int hoursWorked;

    public HourlyEmployee(String name, Department department, double hourlyRate) {
        super(name, department);
        this.hourlyRate = hourlyRate;
        this.hoursWorked = 0;
        this.extraHours = 0;
    }

    public void addExtraHours(int hours) {
        addHours(hours, false);
    }

    public void addHours(int hours) {
        addHours(hours, true);
    }

    private void addHours(int hours, boolean isExtra) {

        if (isExtra) {
            this.extraHours += hours;
        } else {
            this.hoursWorked += hours;
        }
    }

    @Override
    public double getSalary() {

        double baseSalary = hourlyRate * hoursWorked;
        double extraSalary = (hourlyRate * 1.5) * extraHours;
        return baseSalary + extraSalary;
    }
}

Enum Department

package app.empresa;

public enum Department {

    HR("Human Resources"),
    IT("Information Technology"),
    SALES("Sales"),
    MARKETING("Marketing");

    private final String name;

    Department(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    @Override
    public String toString() {
        return getName();
    }
}

Enum MenuOption

package app.empresa;

public enum MenuOption {

    ADD_EMPLOYEE("Agregar Empleado"),
    DELETE_EMPLOYEE("Eliminar Empleado"),
    ADD_HOURS("Agregar Horas"),
    ADD_EXTRA_HOURS("Agregar Horas Extra"),
    ADD_BENEFIT("Agregar Beneficio"),
    DELETE_BENEFIT("Eliminar Beneficio"),
    CALCULATE_SALARY("Calcular Salario"),
    CALCULAR_NOMINA("Calcular Nómina"),
    EXIT("Salir");

    private String name;

    MenuOption(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    @Override
    public String toString() {
        return getName();
    }
}

Clase EmployeeManagementSystem

package app.empresa;

import com.utils.validate.InputValidator;

import java.util.Arrays;
import java.util.Objects;
import java.util.function.Predicate;

public class EmployeeManagementSystem {

    private final Employee[] employees;

    public EmployeeManagementSystem() {
        this.employees = new Employee[500];
        showMenu();
    }

    public void showMenu() {

        MenuOption option;
        do {
            option = InputValidator.validateInput(
                    "Seleccione una opción",
                    MenuOption.values());
            switch (option) {
                case ADD_EMPLOYEE -> addEmployee();
                case DELETE_EMPLOYEE -> deleteEmployee();
                case ADD_HOURS -> addHours();
                case ADD_EXTRA_HOURS -> addExtraHours();
                case ADD_BENEFIT -> addBenefit();
                case DELETE_BENEFIT -> deleteBenefit();
                case CALCULATE_SALARY -> showSalary();
                case CALCULAR_NOMINA -> calculatePayroll();
                case EXIT -> InputValidator.showInfoMessage("Saliendo de la aplicación...");
            }
        } while (option != MenuOption.EXIT);
    }

    private void showSalary() {

        Employee employee = selectEmployee(employees);
        if (employee != null) {
            InputValidator.showInfoMessage(String.format("El salario de %s es: %.2f", employee.getName(), employee.getSalary()));
        } else {
            InputValidator.showErrorMessage("No se pudo calcular el salario, no hay empleados disponibles.");
        }
    }

    private void calculatePayroll() {

        double totalPayroll = Arrays.stream(employees)
                .filter(Objects::nonNull)
                .mapToDouble(Employee::getSalary)
                .sum();
        InputValidator.showInfoMessage(String.format("La nómina total es: %.2f", totalPayroll));
    }

    private void addBenefit() {

        FullTimeEmployee employee = (FullTimeEmployee) selectFullTimeEmployee();
        if (employee != null) {
            if (employee.isBenefitsFull()) {
                InputValidator.showErrorMessage("No se pueden agregar más beneficios a este empleado, la capacidad máxima ha sido alcanzada.");
            } else {
                double benefit = InputValidator.validateInput(
                        "Ingrese el monto del beneficio a agregar",
                        Double.class, s -> s > 0);
                employee.addBenefit(benefit);
                InputValidator.showInfoMessage("Beneficio agregado exitosamente.");
            }
        } else {
            InputValidator.showErrorMessage("No se pudo agregar beneficios, no hay empleados de tiempo completo disponibles.");
        }
    }

    private void deleteBenefit() {

        FullTimeEmployee employee = (FullTimeEmployee) selectFullTimeEmployee();
        if (employee != null) {
            if (employee.hasBenefits()) {
                double benefit = InputValidator.validateInput(
                        "Seleccione el monto del beneficio a eliminar",
                        employee.getBenefits());
                employee.deleteBenefit(benefit);
                InputValidator.showInfoMessage("Beneficio eliminado exitosamente.");
            } else {
                InputValidator.showErrorMessage("No se pueden eliminar beneficios de este empleado, no tiene beneficios registrados.");
            }
        } else {
            InputValidator.showErrorMessage("No se pudo eliminar beneficios, no hay empleados de tiempo completo disponibles.");
        }
    }

    private void addHour(boolean isExtra) {

        HourlyEmployee employee = (HourlyEmployee) selectHoursEmployee();
        if (employee != null) {
            int hours = InputValidator.validateInput(
                    "Ingrese la cantidad de horas a agregar",
                    Integer.class, s -> s > 0);
            if (isExtra) {
                employee.addExtraHours(hours);
                InputValidator.showInfoMessage("Horas extra agregadas exitosamente.");
            } else {
                employee.addHours(hours);
                InputValidator.showInfoMessage("Horas agregadas exitosamente.");
            }
        } else {
            InputValidator.showErrorMessage("No se pudo agregar horas, no hay empleados de horas disponibles.");
        }
    }

    private void addHours() {

        addHour(false);
    }

    private void addExtraHours() {

        addHour(true);
    }

    private Employee selectEmployee(Employee[] employees) {

        if (Arrays.stream(employees).noneMatch(Objects::nonNull)) {
            InputValidator.showErrorMessage("No hay empleados disponibles para esta selección.");
            return null;
        } else {
            return InputValidator.validateInput(
                    "Seleccione un empleado",
                    employees);
        }
    }

    private Employee selectEmployee(Predicate<Employee> predicate) {
        Employee[] filteredEmployees = Arrays.stream(employees)
                .filter(predicate)
                .toArray(Employee[]::new);
        if (filteredEmployees.length == 0) {
            InputValidator.showErrorMessage("No hay empleados disponibles para esta selección.");
            return null;
        } else {
            return selectEmployee(filteredEmployees);
        }
    }

    private Employee selectFullTimeEmployee() {

        return selectEmployee(T -> T instanceof FullTimeEmployee);
    }

    private Employee selectHoursEmployee() {

        return selectEmployee(T -> T instanceof HourlyEmployee);
    }

    private void deleteEmployee() {

        Employee employee = selectEmployee(employees);
        for (int i = 0; i < employees.length; i++) {
            if (employees[i] != null && employees[i].equals(employee)) {
                employees[i] = null;
                InputValidator.showInfoMessage("Empleado eliminado exitosamente.");
                return;
            }
        }
        InputValidator.showErrorMessage("Empleado no encontrado.");
    }

    private void addEmployee() {

        boolean isFull = InputValidator.validateInput(
                "¿El empleado es de tiempo completo? (s/n)",
                Boolean.class);
        Predicate<Double> positiveDouble = s -> s > 0;
        String name = InputValidator.validateInput(
                "Ingrese el nombre del empleado",
                String.class, s -> !s.trim().isEmpty());
        Department department = selectDepartment();
        Employee employee = isFull ?
                new FullTimeEmployee(name, department, InputValidator.validateInput(
                        "Ingrese el salario del empleado",
                        Double.class, positiveDouble)) :
                new HourlyEmployee(name, department, InputValidator.validateInput(
                        "Ingrese la tarifa por hora del empleado",
                        Double.class, positiveDouble));
        addEmployee(employee);
    }

    private void addEmployee(Employee employee) {

        for (int i = 0; i < employees.length; i++) {
            if (employees[i] == null) {
                employees[i] = employee;
                InputValidator.showInfoMessage("Empleado agregado exitosamente.");
                return;
            }
        }
        InputValidator.showErrorMessage("No se pueden agregar más empleados, la capacidad máxima ha sido alcanzada.");
    }

    private Department selectDepartment() {

        return InputValidator.validateInput(
                "Seleccione el departamento",
                Department.values());
    }
}

Conclusión

En este ejemplo, hemos implementado un sistema de gestión de empleados utilizando herencia para definir diferentes tipos de empleados y sobrecarga para manejar la adición de horas y beneficios. Además, hemos utilizado JOptionPane para validar la entrada del usuario y proporcionar una interfaz interactiva. Este enfoque nos permite gestionar eficientemente la información de los empleados y calcular sus salarios de manera flexible.

Copyright Jesús Aurelio Castro Magaña © 2026