Le proprietà autoattive non violano l'incapsulamento?

1

In C #, quando un campo che riceve o imposta richiede logica, usiamo le proprietà. Ad esempio:

private int _age;
public int Age
{
    get
    {
        Console.Writeline("Club member is {0} years old", _age);
    }
    set
    {
        if(value > 0 && value < 120)
        {
            _age = value;
        }
        else
        {
            Console.Writeline("We do not accept unborns nor immortals to our club.");
        }
    }
}

Quando non è richiesta alcuna logica, potremmo usare il molto conciso proprietà auto-implementate :

public string Name {get; set;}

Thos sono molto simili ai campi public poiché puoi leggere e modificare i loro valori da qualsiasi luogo. Vi sono, tuttavia, alcune differenze, poiché Michael Stum riassume molto bene il blog di Jeff Atwood articolo :

  • Reflection works differently on variables vs. properties, so if you rely on reflection, it's easier to use all properties.
  • You can't databind against a variable.
  • Changing a variable to a property is a breaking change. For example:

    TryGetTitle(out book.Title); // requires a variable
    

Come vedo, queste sono differenze molto tecniche: i campi public hanno alcuni vantaggi rispetto alle proprietà auto-implementate e viceversa, ma fondamentalmente, in un punto di vista OOP, sono molto simili: campi che può essere cambiato da qualsiasi classe, e che, per quanto ne so, viola l'incapsulamento.

Quindi perché public campi considerati malvagi a causa della violazione dell'incapsulamento mentre le proprietà auto-implementate sono così grandi?

    
posta Sipo 13.05.2016 - 09:47
fonte

2 risposte

4

La domanda

La domanda è

So why public fields considered evil due to the encapsulation violation while auto-implemented properties are so great?

La risposta a questa domanda è trattata in uno dei punti tecnici che hai notato

Changing a variable to a property is a breaking change

Se pubblichi qualsiasi classe per chiunque (anche per il tuo futuro io), sei tenuto a mantenere questa interfaccia o rompere una quantità arbitraria di codice che dipende da esso. Per sempre.

L'incapsulamento risolve questo problema fornendo (o meglio, descrivendo) un modo per essere certi di poter apportare modifiche all'implementazione in futuro senza violare alcun codice al di fuori della classe. Cioè, l'utilizzo di campi pubblici ti lega a loro indefinitamente, mentre le proprietà generate automaticamente hanno la possibilità di cambiare in futuro senza rompere il codice chiamante.

Vorrei sottolineare che trasformare un campo in una proprietà non è un cambiamento irrisolto in tutti i linguaggi di programmazione, ma è in C #.

Encapsulation

Nella domanda è implicito un altro che vorrei discutere sul fatto che le proprietà possano fornire o meno l'incapsulamento.

Wikipedia definisce l'incapsulamento come due concetti correlati ma separati:

  • A language mechanism for restricting access to some of the object's components.

  • A language construct that facilitates the bundling of data with the methods (or other functions) operating on that data.

La domanda afferma che

[properties are] fields which can be changed from any class, and that, as far as I know, violates encapsulation.

Rifiuto questa affermazione basata su entrambe le definizioni di Wiki. Consentitemi di dare uno scenario di straw man e poi di porre alcune domande su di esso per indagare.

Ho creato una classe chiamata Temperatura. Ha proprietà pubbliche per ottenere e impostare la sua temperatura in gradi Celsius, Fahrenheit e Kelvin. Farà qualsiasi conversione tra loro semplicemente scrivendone uno rispetto a un altro.

Domanda 1: Come viene utilizzata la temperatura?

  1. Leggere e / o scrivere direttamente le proprietà, secondo la descrizione dell'interfaccia di cui sopra

  2. Lettura e / o scrittura di alcuni stati interni che non fanno parte dell'interfaccia pubblica specificata sopra

  3. Qualche altra risposta di cui non sono a conoscenza

Domanda 2: Come viene implementata la temperatura?

  1. Ogni proprietà ha una variabile nascosta di supporto, con ogni setter che aggiorna tutte e tre le variabili di supporto. I getter fanno solo eco alla variabile.

  2. C'è una variabile di supporto (in Rankines) aggiornata da tutti e tre i setter. Ogni getter si converte da Rankines all'unità appropriata al volo.

  3. La temperatura memorizza solo un GUID. Qualsiasi richiesta get / set viene passata con il GUID a un servizio Web, che gestisce l'effettiva attività di conversione.

  4. È impossibile distinguere dall'interfaccia definita, ma uno dei suddetti funzionerebbe (eccezioni di rete modulo).

  5. Qualche altra risposta di cui non sono a conoscenza

Le risposte che selezionerei sono 1 e 4. Cioè, le proprietà definivano qualche interfaccia pubblica per la classe, ma nascondevano come la classe fosse effettivamente implementata. Le proprietà soddisfano "limitare l'accesso ad alcuni dei componenti dell'oggetto" nascondendo ciò che sono anche quei componenti. Insieme alla classe stessa, aiutano anche a "facilitare il raggruppamento dei dati con i metodi (o altre funzioni) che operano su quei dati", potendo condividere le informazioni tra loro.

TL; DR: le proprietà possono (e comunemente sono) utilizzate per supportare l'incapsulamento.

    
risposta data 14.05.2016 - 01:12
fonte
14

Le proprietà non violano l'incapsulamento, perché nascondono l'implementazione sottostante.

Quando si accede a una proprietà, non è necessario sapere esattamente come è implementata: se si tratta di una proprietà automatica, se accede ad altri oggetti o qualsiasi altra cosa. Significa anche che l'implementazione può essere facilmente modificata e tutti gli utenti di tale codice continueranno a funzionare.

Questo non si applica ai campi. L'utente sa sempre come sono implementati e che l'implementazione non può essere modificata senza violare gli utenti del codice (almeno potenzialmente).

    
risposta data 13.05.2016 - 18:36
fonte

Leggi altre domande sui tag