Buscar..


Introducción

Imagine que tiene una clase con algunas variables bastante importantes y que fueron configuradas (por otros programadores desde su código) a valores inaceptables. Su código trajo errores en su código. Como solución, en OOP, permite que el estado de un objeto (almacenado en sus variables) se modifique solo a través de métodos. Ocultar el estado de un objeto y proporcionar toda la interacción a través de los métodos de un objeto se conoce como encapsulación de datos.

Observaciones

Es mucho más fácil comenzar marcando una variable como private y exponerla si es necesario que ocultar una variable que ya es public .

Hay una excepción en la que la encapsulación puede no ser beneficiosa: estructuras de datos "simples" (clases cuyo único propósito es mantener variables).

public class DumbData {
    public String name;
    public int timeStamp;
    public int value;
}

En este caso, la interfaz de la clase es la información que contiene.

Tenga en cuenta que las variables marcadas como final pueden marcarse como public sin violar la encapsulación porque no se pueden cambiar después de establecerlas.

Encapsulamiento para mantener invariantes.

Hay dos partes de una clase: la interfaz y la implementación.

La interfaz es la funcionalidad expuesta de la clase. Sus métodos y variables públicas forman parte de la interfaz.

La implementación es el funcionamiento interno de una clase. Otras clases no deberían necesitar conocer la implementación de una clase.

La encapsulación se refiere a la práctica de ocultar la implementación de una clase de cualquier usuario de esa clase. Esto permite que la clase haga suposiciones sobre su estado interno.

Por ejemplo, toma esta clase que representa un ángulo:

public class Angle {
    
    private double angleInDegrees;
    private double angleInRadians;
    
    public static Angle angleFromDegrees(double degrees){
        Angle a = new Angle();
        a.angleInDegrees = degrees;
        a.angleInRadians = Math.PI*degrees/180;
        return a;
    }
    
    public static Angle angleFromRadians(double radians){
        Angle a = new Angle();
        a.angleInRadians = radians;
        a.angleInDegrees = radians*180/Math.PI;
        return a;
    }
    
    public double getDegrees(){
        return angleInDegrees;
    }
    
    public double getRadians(){
        return angleInRadians;
    }
    
    public void setDegrees(double degrees){
        this.angleInDegrees = degrees;
        this.angleInRadians = Math.PI*degrees/180;
    }
    
    public void setRadians(double radians){
        this.angleInRadians = radians;
        this.angleInDegrees = radians*180/Math.PI;
    }
    private Angle(){}
}

Esta clase se basa en un supuesto básico (o invariante ): angleInDegrees y angleInRadians siempre están sincronizados . Si los miembros de la clase fueran públicos, no habría garantías de que las dos representaciones de ángulos estén correlacionadas.

Encapsulamiento para reducir el acoplamiento.

La encapsulación le permite realizar cambios internos en una clase sin afectar ningún código que llame a la clase. Esto reduce el acoplamiento , o cuánto una clase dada depende de la implementación de otra clase.

Por ejemplo, cambiemos la implementación de la clase Angle del ejemplo anterior:

public class Angle {
    
    private double angleInDegrees;
    
    public static Angle angleFromDegrees(double degrees){
        Angle a = new Angle();
        a.angleInDegrees = degrees;
        return a;
    }
    
    public static Angle angleFromRadians(double radians){
        Angle a = new Angle();
        a.angleInDegrees = radians*180/Math.PI;
        return a;
    }
    
    public double getDegrees(){
        return angleInDegrees;
    }
    
    public double getRadians(){
        return angleInDegrees*Math.PI / 180;
    }
    
    public void setDegrees(double degrees){
        this.angleInDegrees = degrees;
    }
    
    public void setRadians(double radians){
        this.angleInDegrees = radians*180/Math.PI;
    }

    private Angle(){}
}

La implementación de esta clase ha cambiado para que solo almacene una representación del ángulo y calcule el otro ángulo cuando sea necesario.

Sin embargo, la implementación cambió, pero la interfaz no . Si una clase que llama se basó en acceder al método angleInRadians, tendría que cambiarse para usar la nueva versión de Angle . Las clases que llaman no deberían preocuparse por la representación interna de una clase.



Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow