Programación Orientada a Objetos

Semana 6: Excepciones y Patrones de Diseño

El plan para hoy

Comprender el sistema de excepciones en Java Practicar con excepciones verificadas y no verificadas Crear excepciones personalizadas Introducción a los patrones de diseño Categorización y ejemplos de patrones

Jerarquía de Excepciones en Java

Throwable
├── Error
│   ├── OutOfMemoryError
│   ├── StackOverflowError
│   └── ...
└── Exception
    ├── IOException (checked)
    │   ├── FileNotFoundException
    │   └── EOFException
    ├── SQLException (checked)
    └── RuntimeException (unchecked)
        ├── NullPointerException
        ├── ArrayIndexOutOfBoundsException
        └── ArithmeticException

Excepciones Verificadas (Checked)

public class FileProcessor {
    public void readFile(String path) throws IOException {
        File file = new File(path);
        if (!file.exists()) {
            throw new FileNotFoundException("Archivo no encontrado: " + path);
        }
        
        BufferedReader reader = new BufferedReader(new FileReader(file));
        String line = reader.readLine(); // Puede lanzar IOException
        
        if (line == null) {
            throw new IOException("El archivo está vacío");
        }
    }
}

Excepciones No Verificadas (Unchecked)

public class VariousTasks {
    public double divide(int a, int b) {
        // ArithmeticException si b es 0
        return a / b;
    }
    
    public String processText(String text) {
        // NullPointerException si text es null
        return text.toUpperCase();
    }
    
    public int getElement(int[] array, int index) {
        // ArrayIndexOutOfBoundsException si index >= array.length
        return array[index];
    }
}

Creando Excepciones Personalizadas

// Excepción verificada personalizada
public class InsufficientFundsException extends Exception {
    private final double amount;
    private final double balance;
    
    public InsufficientFundsException(String message, double amount, double balance) {
        super(message);
        this.amount = amount;
        this.balance = balance;
    }
    
    public double getAmount() { return amount; }
    public double getBalance() { return balance; }
}

// Excepción no verificada personalizada
public class InvalidProductCodeException extends RuntimeException {
    private final String productCode;
    
    public InvalidProductCodeException(String message, String productCode) {
        super(message);
        this.productCode = productCode;
    }
    
    public String getProductCode() { return productCode; }
}

Uso de Excepciones Personalizadas

public class BankAccount {
    private double balance;
    
    public void withdraw(double amount) throws InsufficientFundsException {
        if (amount > balance) {
            throw new InsufficientFundsException(
                "No hay suficiente saldo para retirar " + amount,
                amount,
                balance
            );
        }
        balance -= amount;
    }
}

public class ProductService {
    public Product findByCode(String code) {
        if (!code.matches("[A-Z]{2}\\d{4}")) {
            throw new InvalidProductCodeException(
                "Código de producto inválido: debe ser 2 letras y 4 números",
                code
            );
        }
        // Buscar producto...
        return product;
    }
}

Introducción a Patrones de Diseño

Los patrones de diseño son soluciones probadas a problemas comunes en el desarrollo de software.

Categorías de Patrones

  1. Patrones Creacionales

    • Controlan la creación de objetos
    • Singleton, Factory Method, Abstract Factory, Builder, Prototype
  2. Patrones Estructurales

    • Composición de clases y objetos
    • Adapter, Bridge, Composite, Decorator, Facade, Flyweight, Proxy
  3. Patrones de Comportamiento

    • Comunicación entre objetos
    • Observer, Strategy, Command, State, Template Method, Iterator, Visitor

Simple Factory Pattern

// Producto base
interface Furniture {
    void assemble();
    void deliver();
}

// Productos concretos
class Chair implements Furniture {
    public void assemble() { 
        System.out.println("Ensamblando silla..."); 
    }
    public void deliver() {
        System.out.println("Entregando silla...");
    }
}

class Table implements Furniture {
    public void assemble() { 
        System.out.println("Ensamblando mesa..."); 
    }
    public void deliver() {
        System.out.println("Entregando mesa...");
    }
}

// Simple Factory
public class FurnitureSimpleFactory {
    public static Furniture createFurniture(String type) {
        if (type == null) {
            throw new IllegalArgumentException("El tipo no puede ser null");
        }
        
        switch (type.toLowerCase()) {
            case "chair":
                return new Chair();
            case "table":
                return new Table();
            default:
                throw new IllegalArgumentException(
                    "Tipo de mueble no soportado: " + type
                );
        }
    }
}

// Uso
public class Client {
    public static void main(String[] args) {
        Furniture chair = FurnitureSimpleFactory.createFurniture("chair");
        chair.assemble();
        chair.deliver();
    }
}

Ejemplo Conceptual: Patrón Factory Method

// Producto
interface Furniture { void assemble(); }

// Productos concretos
class Chair implements Furniture {
    public void assemble() { 
        System.out.println("Ensamblando silla: patas + asiento + respaldo"); 
    }
}
class Table implements Furniture {
    public void assemble() { 
        System.out.println("Ensamblando mesa: patas + superficie"); 
    }
}

// Creador
abstract class FurnitureFactory {
    abstract Furniture createFurniture();
    
    // Método que utiliza el factory
    public void deliverFurniture() {
        Furniture furniture = createFurniture();
        furniture.assemble();
        System.out.println("Empaquetando para envío...");
        System.out.println("Enviando al cliente...");
    }
}

// Creadores concretos
class ChairFactory extends FurnitureFactory {
    Furniture createFurniture() { return new Chair(); }
}
class TableFactory extends FurnitureFactory {
    Furniture createFurniture() { return new Table(); }
}

// Uso
public class Client {
    public static void main(String[] args) {
        FurnitureFactory factory = new ChairFactory();
        factory.deliverFurniture();  // Crea y entrega una silla
    }
}

Ejemplo Conceptual: Patrón Observer

// Observable
interface Subject {
    void attach(Observer observer);
    void detach(Observer observer);
    void notifyObservers();
}

// Observer
interface Observer {
    void update(String message);
}

// Implementación concreta
class NewsAgency implements Subject {
    private List<Observer> observers = new ArrayList<>();
    
    public void attach(Observer observer) {
        observers.add(observer);
    }
    
    public void detach(Observer observer) {
        observers.remove(observer);
    }
    
    public void notifyObservers(String news) {
        for(Observer observer : observers) {
            observer.update(news);
        }
    }
}

¿Preguntas?