Szukaj…


Wprowadzenie

Wyobraź sobie, że masz klasę z kilkoma bardzo ważnymi zmiennymi i zostały one ustawione (przez innych programistów z ich kodu) na niedopuszczalne wartości. Ich kod spowodował błędy w kodzie. Jako rozwiązanie, w OOP zezwalasz na modyfikację stanu obiektu (przechowywanego w jego zmiennych) tylko metodami. Ukrywanie stanu obiektu i zapewnianie wszelkiej interakcji za pomocą metod obiektów nazywane jest enkapsulacją danych.

Uwagi

Znacznie łatwiej jest zacząć od oznaczenia zmiennej private i ujawnić ją, jeśli to konieczne, niż ukryć już public zmienną.

Istnieje jeden wyjątek, w którym enkapsulacja może nie być korzystna: „głupie” struktury danych (klasy, których jedynym celem jest przechowywanie zmiennych).

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

W tym przypadku interfejsem klasy przechowywane przez nią dane.

Należy pamiętać, że zmienne oznaczone jako final można oznaczyć jako public bez naruszania enkapsulacji, ponieważ nie można ich zmienić po ustawieniu.

Kapsułkowanie w celu utrzymania niezmienników

Istnieją dwie części klasy: interfejs i implementacja.

Interfejs to udostępniona funkcjonalność klasy. Jego publiczne metody i zmienne są częścią interfejsu.

Implementacja jest wewnętrznym działaniem klasy. Inne klasy nie powinny wiedzieć o implementacji klasy.

Hermetyzacja odnosi się do praktyki ukrywania implementacji klasy przed użytkownikami tej klasy. To pozwala klasie przyjmować założenia dotyczące jej stanu wewnętrznego.

Weźmy na przykład tę klasę reprezentującą kąt:

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(){}
}

Ta klasa opiera się na podstawowym założeniu (lub niezmienniku ): angleInDegrees i angleInRadians są zawsze zsynchronizowane . Gdyby członkowie klasy byli publiczni, nie byłoby gwarancji, że te dwie reprezentacje kątów są skorelowane.

Kapsułkowanie w celu zmniejszenia sprzężenia

Hermetyzacja umożliwia wprowadzanie wewnętrznych zmian w klasie bez wpływu na kod wywołujący klasę. Zmniejsza to sprzężenie lub to, jak bardzo dana klasa opiera się na implementacji innej klasy.

Na przykład zmieńmy implementację klasy Angle z poprzedniego przykładu:

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(){}
}

Implementacja tej klasy uległa zmianie, dlatego przechowuje tylko jedną reprezentację kąta i oblicza drugi kąt, gdy jest to potrzebne.

Jednak implementacja uległa zmianie, ale interfejs nie . Jeśli klasa wywołująca polegała na dostępie do metody angleInRadians, należałoby ją zmienić, aby użyć nowej wersji Angle . Wywoływanie zajęć nie powinno obchodzić wewnętrznej reprezentacji klasy.



Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow