Saltar a contenido

Encapsulation

El principio de encapsulamiento es uno de los conceptos fundamentales de la programación orientada a objetos. Se refiere a la técnica de ocultar los detalles internos de una clase y exponer solo una interfaz pública bien definida para interactuar con ella.

La encapsulación permite que el código sea más modular y más fácil de mantener, ya que los cambios en la implementación interna de una clase no afectarán a otros componentes del sistema que dependen de ella. Además, la encapsulación promueve la seguridad y la integridad de los datos, ya que solo los métodos de la clase que exponen la interfaz pública pueden modificar los datos internos de la clase.

Para implementar la encapsulación, se definen los atributos y métodos de una clase como públicos, privados o protegidos. Los atributos privados solo son accesibles dentro de la propia clase, mientras que los atributos públicos pueden ser accedidos desde cualquier parte del sistema. Los métodos públicos son aquellos que se exponen a través de la interfaz pública de la clase, mientras que los métodos privados solo son accesibles dentro de la propia clase.

Por ejemplo, considera una clase "CuentaBancaria" que tiene los atributos privados "saldo" y "titular" y los métodos públicos "depositar" y "retirar". La encapsulación permite que los métodos "depositar" y "retirar" actualicen el saldo de la cuenta, mientras que el atributo "saldo" está protegido de modificaciones directas desde fuera de la clase.

En resumen, el principio de encapsulación es un concepto clave de la programación orientada a objetos que se refiere a la técnica de ocultar los detalles internos de una clase y exponer solo una interfaz pública bien definida para interactuar con ella. La encapsulación permite que el código sea más modular, más fácil de mantener y promueve la seguridad y la integridad de los datos.

Ejemplo

Aquí tienes un ejemplo en Java que muestra cómo se puede implementar la encapsulación en una clase Persona:

public class Persona {
    private String nombre;
    private int edad;

    public Persona(String nombre, int edad) {
        this.nombre = nombre;
        this.edad = edad;
    }

    public String getNombre() {
        return nombre;
    }

    public void setNombre(String nombre) {
        this.nombre = nombre;
    }

    public int getEdad() {
        return edad;
    }

    public void setEdad(int edad) {
        this.edad = edad;
    }
}

En este ejemplo, los atributos nombre y edad están definidos como privados, lo que significa que solo pueden ser accedidos desde dentro de la propia clase. En su lugar, se proporcionan métodos públicos getNombre, setNombre, getEdad y setEdad para acceder a los atributos.

Estos métodos permiten leer y escribir los valores de los atributos de la clase, pero el código externo no tiene acceso directo a ellos. De esta manera, la clase Persona encapsula la información sobre el nombre y la edad de una persona, lo que significa que otros componentes del sistema solo pueden interactuar con ella a través de la interfaz pública proporcionada por los métodos get y set.

Encapsulación de comportamiento

La encapsulación de comportamiento se refiere a la técnica de ocultar los detalles de implementación de un comportamiento complejo detrás de una interfaz simple y fácil de usar. En lugar de exponer todos los detalles de implementación, la encapsulación de comportamiento proporciona una interfaz clara y bien definida para interactuar con el comportamiento.

La encapsulación de comportamiento se utiliza a menudo en el diseño de patrones de software, como el patrón de diseño State o el patrón de diseño Strategy. En estos patrones, la encapsulación de comportamiento se logra mediante la definición de una interfaz común para diferentes implementaciones de comportamiento.

Por ejemplo, considera un sistema de procesamiento de pagos que necesita soportar diferentes métodos de pago, como tarjetas de crédito, transferencias bancarias y PayPal. En lugar de exponer todos los detalles de implementación de cada método de pago, se puede definir una interfaz común MetodoPago que define los métodos necesarios para procesar un pago:

public interface MetodoPago {
    public void procesarPago(double cantidad);
    public String getNombreMetodoPago();
}

Luego, se pueden implementar diferentes clases que implementen la interfaz MetodoPago, cada una con su propia implementación de los métodos procesarPago y getNombreMetodoPago para soportar diferentes métodos de pago. Estas clases pueden encapsular todos los detalles de implementación de su método de pago correspondiente detrás de la interfaz común MetodoPago.

public class TarjetaCredito implements MetodoPago {
    public void procesarPago(double cantidad) {
        // implementación de procesamiento de pago con tarjeta de crédito
    }
    public String getNombreMetodoPago() {
        return "Tarjeta de crédito";
    }
}

public class TransferenciaBancaria implements MetodoPago {
    public void procesarPago(double cantidad) {
        // implementación de procesamiento de pago con transferencia bancaria
    }
    public String getNombreMetodoPago() {
        return "Transferencia bancaria";
    }
}

public class PayPal implements MetodoPago {
    public void procesarPago(double cantidad) {
        // implementación de procesamiento de pago con PayPal
    }
    public String getNombreMetodoPago() {
        return "PayPal";
    }
}

Con la encapsulación de comportamiento, el resto del sistema solo necesita interactuar con la interfaz común MetodoPago para procesar un pago, sin preocuparse por los detalles de implementación de cada método de pago individual. Esto hace que el sistema sea más modular, más fácil de mantener y más escalable en caso de que se agreguen nuevos métodos de pago en el futuro.

¿Cómo se aplicaría este principio?

classDiagram
    class Animal {
        -name: String
        -age: Int
        +setName(name: String): void
        +setAge(age: Int): void
        +getName(): String
        +getAge(): Int
    }

    class Dog {
        -breed: String
        -weight: Double
        +setBreed(breed: String): void
        +setWeight(weight: Double): void
        +getBreed(): String
        +getWeight(): Double
    }

    Animal <|-- Dog

En este ejemplo, se tiene una clase llamada Animal que representa un animal genérico con atributos privados de nombre y edad, y métodos públicos para establecer y obtener esos atributos. Luego, se tiene otra clase llamada Dog que hereda de la clase Animal y agrega atributos privados de raza y peso, así como métodos públicos para establecer y obtener esos atributos específicos de un perro.

Dog es una subclase de Animal, lo que significa que Dog hereda los atributos y métodos de Animal, pero también puede tener sus propios atributos y métodos únicos.

Este ejemplo ilustra el principio de encapsulación, que es la idea de que los detalles internos de una clase (como los atributos y métodos privados) deben estar ocultos al mundo exterior. En este ejemplo, la clase Animal encapsula los detalles de nombre y edad, y la clase Dog encapsula los detalles de raza y peso. Esto permite que los cambios internos en una clase no afecten a otras partes del sistema que utilizan esa clase, lo que a su vez facilita el mantenimiento y la evolución del sistema.