Programación Orientada a Objetos

POO

Introducción a la POO

Contenido

  • Introducción a Programación Orientada a Objetos

  •  Clases

  •  Objetos

  •  UML

  •  Definición de clases en Java

Introducción a Programación Orientada a Objetos

  • Paradigma de programación.
  • Abstracción de la realidad.
  • Diferente del paradigma procedimental.
  • Formalización de los Tipos Abstractos de Datos (TAD).
  • Muchos lenguajes de programación lo soportan:
    • Java
    • Python
    • C++
    • C#
    • Entre otros.

Objeto

Clase

Herencia

Polimorfismo

Abstracción

Encapsulamiento

Desarrollo de Software Orientado a Objetos

  • Análisis:
    • Analizar el problema, sistema o tarea.
    • Identificar los objetos y las relaciones entre estos.
    • Identificar requerimientos.
  • Diseño:
    • Convertir los requerimientos en especificaciones para la implementación.
    • Definir clases, objetos y comportamientos.
  • Implementación: Convertir el diseño en un programa funcional.

Análisis

Diseño

Implementación

Ejemplo de requerimientos

  • Buscar un libro.
  • Buscar un producto.
  • Ver recomendaciones.
  • Cargar un documento.
  • Inscribir una asignatura.
  • Consultar la información de una persona.

Clase

  • Abstracta.
  • Conjunto de objetos que comparten una estructura bien definida.
  • No representa a una entidad individual.
  • Es definida dependiendo de las necesidades (requerimientos) del problema.
  • Cualquier cosa se puede modelar como una clase.

Clase Carro

Objeto

  • Concreto.
  • Concepto, abstracción o cosa con límites bien definidos.
  • Representa una entidad individual del conjunto de elementos que la clase define.
  • Es una colección de datos con comportamientos asociados.
  • Son instanciados a partir de una clase.

Objeto

Rayo Mcqueen

Tesla

Audi

Atributos

  • Son datos que representan las características individuales de un objeto.
  • En la clase se define un conjunto de atributos que son parte de todos los objetos de dicha clase.
  • Cada objeto puede tener distintos valores en sus atributos.
  • Corresponden a un tipo de dato específico:
    • Genéricos: entero, float, string, booleano, byte.
    • Colecciones: matrices, listas, tuplas, diccionarios, arboles, grafos.
    • Otras Clases específicas de la aplicación

Un objeto puede tener infinitos atributos, pero no todos son relevantes para un problema dado

Atributos

Clase Carro

Objeto

Tesla

Audi

color: string;
modelo: int;

precio_euros: float;

tieneGPS: boolean;

color = blanco;
modelo = 2022;

precio_euros = 100000;

tieneGPS =  true;

color = rojo;
modelo = 2024;

precio_euros = 90000;

tieneGPS =  false;

Métodos

  • Describen el comportamiento de los objetos.
  • Son definidos dentro de la clase.
  • A nivel de programación, son funciones que: tienen acceso a los atributos del objeto, pueden admitir parámetros y retornar valores.

Diferentes objetos de una misma clase pueden reaccionar de distintas maneras a la ejecución de un método

Métodos

Clase Carro

  • encender();
  • actualizarPrecio(double nuevoPrecio);
  • activarAlarma();
  • obtenerKilometraje();
  • recargarCombustible(double litros);
  • acelerar();

Ejemplo

UML

  • Lenguaje unificado de modelado (Unified Modeling Language).
  • Usado para describir modelos de sistemas.
  • En POO, uno de los diagramas más usados son los Diagramas de Clases que:
    • Describen las Clases, sus Atributos y sus Métodos.
    • Describen Relaciones entre clases.

Tipos de relaciones:

  • Asociación
  • Agregación
  • Herencia
  • Multiplicidad
  • Encapsulamiento

UML Definición de clases

  • Cada clase se representa con un rectángulo dividido en tres secciones:
    • La primera sección contiene el nombre de la clase
    • La segunda sección contiene los atributos de la clase.
    • La tercera sección contiene los métodos de la clase.
  • No es necesario que las dos últimas secciones se utilicen.

Definicion de clase JAVA

public class Carro {
    // Atributos
    public String color;
    public int modelo;
    public float precio_euros;
    public boolean tieneGPS;

    // Constructor
    public Carro(String color, int modelo, float precio_euros, boolean tieneGPS) {
        this.color = color;
        this.modelo = modelo;
        this.precio_euros = precio_euros;
        this.tieneGPS = tieneGPS;
    }

    // Métodos
    public void encender() {
        // Implementación del método encender
    }

    public void actualizarPrecio(double nuevoPrecio) {
        // Implementación del método actualizarPrecio
    }

    public void activarAlarma() {
        // Implementación del método activarAlarma
    }

    public double obtenerKilometraje() {
        // Implementación del método obtenerKilometraje
    }

    public void recargarCombustible(double litros) {
        // Implementación del método recargarCombustible
    }

    public void acelerar() {
        // Implementación del método acelerar
    }
}

Encapsulamiento y relaciones entre clases

Contenido

  •   Encapsulamiento

  •  Multiplicidad

  •  Relaciones entre clases

Encapsulamiento

  • El paradigma de programación procedimental tiene poca
    protección de los datos
    •  Las variables globales de un programa pueden ser accedidas y
      alteradas por cualquier procedimiento del programa.
  • El encapsulamiento hace referencia a ocultar los detalles
    de implementación internos del objeto
     (atributos y
    métodos) a los demás.
    • Cada objeto es dueño único de su información.
    • Puede definir parámetros de acceso.
  • Permite definir la interfaz pública de un objeto.

Encapsulamiento

Niveles de acceso o visibilidad

  • Público: Se tiene acceso a los atributos o métodos sin restricción alguna. En UML se representa con el símbolo ‘ + ’.

 

  • Privado: Ninguna clase externa puede acceder y mucho menos modificar los atributos o los métodos de esta clase. En UML se representa con el símbolo ‘ - ’.

 

  • Protegido: Sólo las clases hijas tienen acceso a los atributos o métodos definidos en la clase padre. En UML se representa con el símbolo ‘ # ’.

Encapsulamiento en Java

public class MyClass {
    // Atributos con diferentes niveles de acceso
    public int x;
    protected int y;
    private int z;
    
    // Constructor
    public MyClass(int x, int y, int z) {
        this.x = x;
        this.y = y;
        this.z = z;
    }
    
    // Método público
    public void publicMethod() {
        // Do something
    }
    
    // Método protegido
    protected void protectedMethod() {
        // Do something
    }
    
    // Método privado
    private void privateMethod() {
        // Do something
    }
}

Encapsulamiento

  • Para acceder a atributos privados es necesario usar métodos públicos.
  • Estos métodos son conocidos como getters y setters:
// Getter
    public type getAttribute() {
        if (validationCondition) {
            return this.attribute;
        }
        return null;
    }
// Setter
    public void setAttribute(type newValue) {
        if (validationCondition) {
            this.attribute = newValue;
        }
    }

Multiplicidad

Determina cuántos objetos de cada tipo intervienen en una relación

Indicador Significado
0..1 Cero o uno
1 Solo uno
0..* Cero o más
1..* Uno o más
n Solo n (n > 1)
0..n Cero a n (n > 1)
1..n Uno a n (n > 1)

Multiplicidad

Asociaciones

Asociación bidireccional

  • Conexión entre dos clases donde ambas se referencia mutuamente.
  • Un objeto de una clase conoce a un objeto de la otra clase, y viceversa.
  • Los elementos de ambas clases pueden existir de manera independiente.
  • Los elementos de ambas clases son conscientes de la relación entre ellos.

Asociaciones

Asociación unidireccional

  • Una clase conoce a otra clase, pero no al revés.
  • Solo una de las clases tiene una referencia a la otra, y la relación NO es recíproca.
  • La relación de las clases es en una dirección.
  • Los elementos de ambas clases pueden existir de manera independiente.
  • Sólo los elementos de una clase son conscientes de la relación entre ellos.

Asociaciones

Asociación reflexiva

  • Una clase está asociada consigo misma.
  • Un objeto de una clase se relaciona con otro objeto de la misma clase.
  • Los objetos tienen una relación jerárquica, de dependencia o de agrupación entre sí.
  • Una clase puede estar relacionada con otras instancias del mismo tipo.

Agregación

Agregación básica

  • Una clase (el todo) contiene o está compuesta por otra clase.
    Los elementos de ambas clases pueden existir de manera independiente.
  • Una clase se compone / contiene / posee / construye a partir de instancias de otra clase.
  • Estas instancias no son parte fundamental de la clase, pero influyen en su funcionamiento.

Agregación

Agregación de composición

  • Representa una asociación fuerte entre dos clases.
  • Una clase (el todo) está compuesta por otra clase (la parte)
  • Una clase se compone / contiene / posee / construye a partir de instancias de otra clase.
  • Estas instancias son parte fundamental de la clase.
  • Los objetos de la clase relacionada no pueden existir sin el objeto de la clase compuesta.

Ejemplo

Ejercicios

  1. Diseñe un diagrama UML para modelar un juego de ajedrez. Debe usar mínimo 3 de las relaciones mencionadas previamente
  2. Diseñe un diagrama UML para modelar el registro de materias en la universidad.

Herencia y Polimorfismo

Contenido

  •   Herencia

    • Básica

    • Múltiple

  •  Polimorfismo

    • Interno

      • Sobrecarga de métodos
    • Externo

      • Sobreescritura de métodos
      • Referencias múltiples

Herencia

  • Una clase puede ser demasiado general para describir la naturaleza de todos los objetos que representa.
    •  Algunos objetos presentan atributos y comportamientos diferentes.
    • Podemos pensar que debemos crear una clase para cada uno de ellos.
  • Si se tienen mútiples clases con varios elementos en común:
    • Genera repetición de código.
    • Alto costo de mantenimiento.
    • El cambio se debe repetir en cada copia del código.

Herencia básica

  • Los aspectos comunes de varias clases se pueden concentrar en una única clase de “mayor nivel” que las agrupe, conocida como la clase padre.
     
  • Las clases derivadas tendrán los atributos y los métodos de la clase padre, y adicionalmente podrá definir sus propios métodos y atributos.
     
  • Al instanciar un objeto de una clase derivada es necesario instanciar los atributos del padre.
    • Para instanciar estos atributos se utiliza el super, que generalmente referencia a la clase padre.

Herencia básica

// Clase padre
class Animal {
    protected String nombre;
    protected int edad;
    
    public Animal(String nombre, int edad) {
        this.nombre = nombre;
        this.edad = edad;
    }
    
    public void hacerSonido() {
        System.out.println("El animal hace un sonido");
    }
}
// Clase derivada (hija)
class Perro extends Animal {
    private String raza;
    
    public Perro(String nombre, int edad, String raza) {
        super(nombre, edad);  // Llama atributos del padre
        this.raza = raza;
    }
    
    @Override
    public void hacerSonido() {
        System.out.println("¡Guau!");
    }
}

Herencia básica

Representación de la herencia en UML: Donde Clase1 es la clase padre y Clase2 es la clase hija o clase derivada.

La clase hija en UML no debe ser escrita con los atributos o métodos que toma del padre. Solo se escriben nuevos atributos, nuevos métodos o métodos que fueron sobreescritos o modificados.

Herencia multinivel

  • También es posible tener múltiples niveles de herencia, es decir una clase derivada que a su vez puede ser una clase padre
  • Son conocidas como herencia multinivel.
  • En Java todas las clases extienden de la clase Object.

Herencia múltiple

  • Una clase puede heredar de múltiples clases.
  • Esto genera algunos problemas:
    • Ambas clases padre implementen un mismo método con diferente funcionalidad.
    • Problema del diamante.
  • Algunos lenguajes de programación no lo soportan, pero esto puede solucionarse con el uso de interfaces.

Polimorfismo

Es uno de los grandes aportes de la programación orientada a objetos.

 

Definiciones:

  • La capacidad de un método o una clase de poder asumir varias formas.
  • La capacidad de tratar una clase de forma diferente, dependiendo de la subclase que se implemente.
  • La capacidad de producir comportamientos diferentes en función de la subclase que se esté utilizando, sin tener que saber explícitamente cuál es la subclase en realidad.

Polimorfismo

Polimorfismo Interno - Sobrecarga de métodos

  • Dentro de una clase se pueden tener varios métodos con el mismo nombre.
  • Estos se distinguen por los diferentes conjuntos o permutaciones (en cuanto al tipo de datos) de los parámetros de entrada.
public class Calculadora {
    public int sumar(int a, int b) {
        return a + b;
    }

    public int sumar(int a, int b, int c) {
        return a + b + c;
    }

    public double sumar(double a, double b) {
        return a + b;
    }

    public String sumar(String a, String b) {
        return a + b;
    }
}

Polimorfismo

Polimorfismo Externo - Sobreescritura de métodos

  • Cuando una clase hija quiere reescribir el método heredado de su clase padre.
  • El nombre del método a reescribir debe ser exactamente igual que el del padre.
// Clase padre
class Instrumento {
    public void tocar() {
        System.out.println("Tocando un instrumento");
    }
}

// Clase hija
class Guitarra extends Instrumento {
    @Override
    public void tocar() {
        System.out.println("Tocando la guitarra con las cuerdas");
    }
}
Instrumento obj1 = new Instrumento();
obj1.tocar();
>> Tocando un instrumento

Guitarra obj2 = new Guitarra();
obj2.tocar();
>> Tocando la guitarra con las cuerdas

Polimorfismo

Polimorfismo Externo - Múltiple referencia

Un objeto puede ser referenciado de múltiples maneras:

  • La clase base (Object).
  • Su propia clase.
  • Su clase padre.
  • Sus interfaces.
// Clase padre
class Instrumento {
    public void tocar() {
        System.out.println("Tocando un instrumento");
    }
}

// Clase hija
class Guitarra extends Instrumento {
    @Override
    public void tocar() {
        System.out.println("Tocando la guitarra con las cuerdas");
    }
}
Object obj = new Guitarra();

Instrumento obj = new Guitarra();

Guitarra obj = new Guitarra();

Interfaces y Clases Abstractas

Contenido

  • Clases abstractas

    • Herencia abstracta

  • Interfaces

  • Otros modificadores

    • Estático (static)

    • Final

  • Enumeraciones

Clases abstractas

  • Si la clase define objetos muy genéricos que no existen en la realidad (o en el sistema de información), se puede considerar una clase abstracta.
  • Son clases que no pueden ser instanciadas.
  • Una clase que incluye al menos un método abstracto es una clase abstracta.
  • De las clases abstractas se pueden derivar clases concretas.
public abstract class FiguraGeometrica {
	
    protected String color;
    
    //Constructor
    public Figura(String color) {
    	this.color = color;
    }
    
    //Métodos abtractos
    public abstract double area();
    public abstract double perimetro();
    
    //Método no abstracto
    public String getColor() {
    	return color;
    }
}

Lo abstracto esta en cursiva(Italic)

Herencia abstracta

  • Una relación de herencia es abstracta cuando la clase padre es una clase abstracta.
  • Las clases hijas deben:
    • Instanciar los atributos de la clase padre mediante el super.
    • Definir (sobrescribir) los métodos abstractos de la clase padre.
  • La clase abstracta puede ser utilizada para referenciar a un objeto concreto de una de sus clases hijas (Polimorfismo externo).
public class Rectangulo extends FiguraGeometrica {
    private double base;
    private double altura;
    
    public Rectangulo(String color, double base, double altura) {
        super(color);
        this.base = base;
        this.altura = altura;
    }
    
    @Override
    public double area() {
        return base * altura;
    }
    
    @Override
    public double perimetro() {
        return 2 * (base + altura);
    }
}

Interfaces

  • Una interfaz contiene:
    • Conjunto de servicios que deben ser exhibidos por una clase (Varios métodos abstractos), solo se define nombre, salidas y entradas. No tiene código asociado.
    • Constantes.
  • Si una clase implementa una interfaz, debe definir el código de los métodos enumerados en la interfaz.
  • Una clase puede implementar varias interfaces.
  • Las interfaces permiten que clases diferentes puedan compartir un mismo conjunto de métodos, aunque estas clases no estén relacionadas entre sí.

Interfaces

// Definición de la interfaz
public interface Sonido {
    public void hacerSonido();
    public void ajustarVolumen(int nivel);
}

// Clase que implementa la interfaz
public class Guitarra implements Sonido {
    private String marca;
    private int volumen;
    
    public Guitarra(String marca) {
        this.marca = marca;
        this.volumen = 5; // volumen por defecto
    }
    
    @Override
    public void hacerSonido() {
        System.out.println("La guitarra " + marca + " hace notas musicales");
    }
    
    @Override
    public void ajustarVolumen(int nivel) {
        this.volumen = nivel;
        System.out.println("Volumen ajustado a: " + nivel);
    }
}

Ejemplo

Interfaces

public class Despertador implements Sonido {
    private String hora;
    private int volumen;
    
    public Despertador(String hora) {
        this.hora = hora;
        this.volumen = 10;
    }
    
    @Override
    public void hacerSonido() {
        System.out.println("El despertador hace RING RING a las " + hora);
    }
    
    @Override
    public void ajustarVolumen(int nivel) {
        this.volumen = nivel;
        System.out.println("Alarma ajustada a volumen: " + nivel);
    }
}

Ejemplo

Otros modificadores

Estático(static)

  • Este modificador se utiliza para definir que el método o atributo NO depende de una instancia sino de una clase:
    • El método/atributo puede ser invocado sin necesidad de una instancia de la clase.
 public class MyClass {
    
    public static int x = 5;
    
    public static int add(int value) {
        return value + x;
    }
    
}

 System.out.println(MyClass.x);
 >> 5
 
 System.out.println(MyClass.add(18));
 >> 25

Otros modificadores

Final

  • Este modificador se utiliza para definir que el valor de un atributo NO va a cambiar después de ser inicializado
    • Usualmente representan constantes.
private final String name;

public static final double PI = 3.1415;
  • Se puede utilizar para definir que una clase NO puede tener clases hijas.
public final class Student extends Person{...}

Enumeraciones

  • Una enumeración es una clase "especial" que representa un grupo de constantes.
  • Limitan la creación de objetos a los especificados explícitamente en la implementación de la clase.
    • Tienen métodos heredados de su clase padre Enum.
    • En caso de tener constructor, debe ser privado o protegido para que no se puedan crear nuevos objetos.
  • Se pueden definir dentro de una clase.
public enum DiaSemana {
    LUNES,
    MARTES,
    MIERCOLES,
    JUEVES,
    VIERNES,
    SABADO,
    DOMINGO
}

Enumeraciones

public enum TipoVehiculo {
    COCHE(4),
    MOTO(2),
    CAMION(6);

    private final int numRuedas;

    // Constructor privado
    private TipoVehiculo(int numRuedas) {
        this.numRuedas = numRuedas;
    }

    public int getNumRuedas() {
        return numRuedas;
    }
}

Otro ejemplo

Ventajas

  • Tipo seguro: no puedes asignar valores que no estén definidos
  • Conjunto cerrado de valores
  • Pueden tener métodos y atributos
  • Útiles para representar estados, tipos o categorías fijas
  • Mejoran la legibilidad del código

Casos comunes de uso

  • Estados de un proceso (INICIADO, EN_PROCESO, FINALIZADO)
  • Días de la semana
  • Meses del año
  • Tipos de usuario (ADMIN, USUARIO, INVITADO)
  • Categorías de productos
  • Niveles de acceso

Pruebas (Testing)

Contenido

  • Pruebas (Testing)

    • Principios del testing

    • Tipos de pruebas

  • Plan de pruebas

  • Introducción a pruebas unitarias en Java

Pruebas

Es el proceso de evaluar y verificar que un producto o aplicación de software lleve a cabo su propósito correctamente.

Beneficios de las pruebas:

  • Prevención de errores.
  • Reducción de los costos de desarrollo.
  • Mejora del rendimiento de la aplicación

Pruebas

Principios:

  1. El testing sirve para demostrar defectos
  2. No es posible realizar testing de software exhaustivo
  3. Necesidad de realizar pruebas tempranas
  4. Agrupación de defectos.
  5. Paradoja del pesticida.
  6. Se debe tener en cuenta el contexto.
  7. La ausencia de errores es una falacia.

Pruebas

Tipos de pruebas:

  • Pruebas unitarias
  • Pruebas de integración
  • Pruebas funcionales
  • Pruebas de extremo a extremo
  • Pruebas de aceptación
  • Pruebas de rendimiento.
  • Pruebas de humo

Pruebas

Pruebas unitarias

  • Pruebas de muy bajo nivel.
  • Se realizan cerca de la fuente de la aplicación.
  • Consisten en probar métodos y funciones individuales de:
    1) Clases
    2) Componentes
    3) Módulos
  • Son las primeras que se deben realizar durante todo el proceso de desarrollo.

Pruebas

Pruebas de integración

  • Se encargan de verificar que los distintos módulos o servicios utilizados por la aplicación funcionen bien en conjunto, es decir se integren de la manera correcta.
  • Los sistemas que interactúan entre si pueden ser internos o externos

Pruebas

Pruebas funcionales

  • Se centran en los requisitos empresariales de una aplicación.
  • Solo verifican el resultado de una acción.
  • No comprueban los estados intermedios del sistema al realizar la acción.
  • Son consideradas pruebas de caja negra, donde solo se controla la entrada y salida mas no se ve el proceso interno.

Pruebas

Pruebas de extremo a extremo

  • Replican el comportamiento que puede tomar un usuario con el software en un entorno de aplicación completo.
  • Verifican que diversos flujos de usuario funcionen de manera correspondiente.
  • Validan que los flujos críticos del sistema funcionan correctamente.

Pruebas

Pruebas de aceptación

  • Son pruebas formales que verifican si un sistema satisface los requisitos empresariales. Se deben definir los criterios de aceptación con anterioridad.
  • Requieren que se esté ejecutando toda la aplicación durante las pruebas. Se centran en replicar conductas de los usuarios.
  • Se puede medir el rendimiento del sistema y rechazar cambios si no se han cumplido algunos objetivos.

Pruebas

Pruebas de rendimiento

  • Evalúan el rendimiento de un sistema con una carga de trabajo definida.
  • Ayudan a medir la fiabilidad, velocidad, escalabilidad y la capacidad de respuesta de una aplicación
    • Cumplir con los requisitos de rendimiento.
    • Localizar cuellos de botella.
    • Medir la estabilidad durante los picos de tráfico.

Pruebas

Pruebas de humo

  • Pruebas básicas que sirven para comprobar el funcionamiento básico de la aplicación.
  • Su objetivo es ofrecer la seguridad de que las principales funciones del sistema se ejecuten según lo previsto.
  • Determinan si la aplicación está preparada para ser sometida por pruebas más exhaustivas.
  • Si no se superan estas pruebas no se programan pruebas más complejas.

Plan de pruebas

  • Tiene como objetivo orientar el esfuerzo de pruebas, definiendo las pruebas más importantes según sea el caso.
  • Se sugiere utilizar las pruebas establecidas por el ISTQB(International Software Testing Qualifications Board).
  • Se debe tener en cuenta:
    • Objetivos de negocio que tiene que cumplir el software.
    • Calendario del proyecto.
    • Metodología usada para del desarrollo.

Plan de pruebas

Plan de pruebas

Plan de pruebas

Plan de pruebas

Introducción a pruebas unitarias en Java

  • Para realizar pruebas unitarias en Java se utiliza la librería junit.Es una librería externa que debe ser descargada y añadida al proyecto.
  • Las librerías deben ser incluidas en el apartado de Test Libraries del proyecto.
  • Una prueba cuenta con 3 partes:
    • Given: Condiciones iniciales de la prueba.
    • When: Ejecución de la prueba.
    • Then: Verificación de los valores de prueba.
public class MyClass {

	private int number;
    
 	public MyClass(int number) {
    	this.number = number;
    }
    
 	public int add(int value) {
 		return this.number + value;
 	}
 }
import static org.junit.Assert.assertEquals;
import org.junit.Test;

public class MyClassTest {

 	@Test
 	public void testAdd() throws Throwable {
 		// Given
		MyClass obj = new MyClass(5);
        
        // When
        int value = 12;
        int result = obj.add(value);
        
        // Then
		assertEquals(17, result);
	}
} 
Made with Slides.com