CodeGym /Corsi /C# SELF /Incapsulamento e modificatori di accesso

Incapsulamento e modificatori di accesso

C# SELF
Livello 17 , Lezione 0
Disponibile

1. Introduzione

Immagina di progettare un'auto moderna. Dentro ci sono centinaia di parti complesse, elettronica delicata, impostazioni fini. Ovviamente, nessuno dovrebbe poter accedere facilmente al blocco di controllo del motore e iniziare a girare qualche vite a caso. Se ognuno mette mano dove non dovrebbe, la macchina potrebbe comportarsi in modo imprevedibile e tu dovresti fare un check-up per capire chi ha rotto cosa.

Lo stesso vale nella programmazione. Quando crei una classe, vuoi proteggere le sue "interiora" dalle mani altrui — così nessuno rovina accidentalmente dati importanti o interferisce con metodi che il mondo esterno non dovrebbe nemmeno conoscere. Ecco il senso dell'incapsulamento — uno dei tre principi chiave della programmazione orientata agli oggetti.

L'incapsulamento ti permette di nascondere i dettagli dell'implementazione e di definire chiaramente cosa è accessibile "da fuori" e cosa deve restare dentro. È come se aprissi il cassetto portaoggetti all'utente, ma tenessi il cofano ben chiuso a chiave. La classe decide da sola quali dati mostrare al codice esterno e quali tenere segreti. Così il codice diventa più affidabile, logico e facile da mantenere.

Per dirla in modo più preciso, incapsulamento è un modo per unire dati (campi) e comportamento (metodi) collegati a questi dati in un'unica struttura, limitando l'accesso diretto ai componenti interni dell'oggetto.

2. Modificatori di accesso: difendiamo il nostro territorio

In C# (e in altri linguaggi OOP) incapsulamento si realizza tramite i modificatori di accesso. Sono delle "etichette" che definiscono quali membri della classe (campi, metodi, proprietà, ecc.) sono accessibili dall'esterno e quali solo dall'interno.

Li abbiamo già incontrati, ma ricordiamo cosa sappiamo e allarghiamo un po' la lista dei modificatori:

Modificatore Accessibile da...
public
A tutti! Qualsiasi codice nel progetto (e anche fuori, se il progetto è una libreria)
private
Solo dall'interno della stessa classe
protected
Da questa classe e da tutte le sue sottoclassi
internal
Solo all'interno dell'assembly (progetto) corrente
protected internal
O dall'assembly corrente, o da una sottoclasse
private protected
Solo da una sottoclasse all'interno dell'assembly corrente

In questa lezione ci concentriamo sui più usati: public, private e accenniamo a protected, per non farti fondere il cervello.

Separiamo interno ed esterno

Dai, scriviamo una classe Dog:


public class Dog
{
    public string Name;
    public int Age;

    public void Bark()
    {
        Console.WriteLine($"{Name} dice: Bau!");
    }
}

Qui tutti i campi e i metodi sono dichiarati public. Questo significa che chiunque può cambiare il nome o l'età del cane:

Dog rex = new Dog("Rex", 5);
rex.Name = "Sharik"; // Cambio di identità inaspettato!
rex.Age = -999;     // Problemi seri con l'età

Eppure i campi Name e Age sono dati fondamentali che non vuoi lasciare in mano a chiunque.

Così non si fa

Lasciando tutti i campi public, rischi di rompere la logica della classe: qualsiasi intervento esterno può rendere l'oggetto non valido. Per esempio, dare al cane un'età negativa o un nome tipo "%$#!??".

3. Nascondiamo i campi: usiamo private

Di solito i campi di una classe si fanno privati (con il modificatore private). Questo significa che puoi cambiarne il valore solo dall'interno della classe stessa, e mai da fuori.


public class Dog
{
    private string name;
    private int age;

    public void Bark()
    {
        Console.WriteLine($"{name} dice: Bau!");
    }
}

Ora se provi ad accedere ai campi da fuori:

Dog rex = new Dog("Rex", 5);
rex.name = "Sharik";  // Errore di compilazione

Il compilatore ti dice subito: "Accesso negato!".

Perché così rigido? E la flessibilità?

Tutta la "flessibilità" si ottiene tramite metodi speciali o proprietà (ne parleremo meglio nella prossima lezione), che permettono di controllare l'accesso e modificare i dati solo secondo certe regole.

4. Incapsulamento in pratica: esempio con controllo

Immagina che vogliamo impedire che un cane abbia un'età negativa:


public class Dog
{
    private string name;
    private int age;

    public Dog(string name, int age)
    {
        this.name = name;
        if (age >= 0)
            this.age = age;
        else
            this.age = 0; // Non permettiamo un'età "strana"
    }

    public void Bark()
    {
        Console.WriteLine($"{name} dice: Bau!");
    }

    // Metodo per cambiare l'età in modo sicuro
    public void SetAge(int newAge)
    {
        if (newAge >= 0)
            age = newAge;
        // Puoi aggiungere un else: messaggio di valore non valido
    }
}

Ora nessuno da fuori può rovinare i campi direttamente. Per cambiare l'età c'è un metodo apposito che fa il controllo necessario.

5. Campi contro metodi di accesso (getter/setter)

Questo modo — rendere i campi private e fornire metodi per lavorarci — si chiama incapsulamento dei dati (data encapsulation). Per leggere il valore di un campo spesso si crea un metodo getter, per scrivere — un setter.


public class Dog
{
    private string name;

    public Dog(string name)
    {
        this.name = name;
    }

    public string GetName()
    {
        return name;
    }

    public void SetName(string newName)
    {
        // Qui puoi aggiungere un controllo sul nome
        name = newName;
    }
}

Ma! Con l'arrivo delle proprietà (properties) in C#, questi metodi si usano sempre meno — le proprietà rendono il codice molto più pulito e comodo (ne parleremo nella prossima lezione).

6. Modificatori di accesso per metodi e classi

I campi non sono tutto! I modificatori di accesso si usano anche per i metodi (funzioni membro della classe) e persino per le classi stesse.

I metodi che servono solo all'interno della classe (tipo funzioni di supporto per la logica interna), di solito si fanno private.

I metodi pubblici sono il cosiddetto "interfaccia" della classe (da non confondere con la parola chiave interface), cioè quello che l'utente della classe può usare.

7. Errori tipici con l'incapsulamento

Errore n°1: tutto viene dichiarato public.
Sembra che più cose sono accessibili, più è facile usare la classe. In realtà così apri l'accesso a parti interne che non dovrebbero essere cambiate da fuori. Questo rende il codice vulnerabile e imprevedibile, soprattutto nei progetti grandi.

Errore n°2: cambiare il modificatore di accesso rompe il codice esterno.
Durante il refactoring puoi cambiare per sbaglio il modificatore di accesso di un metodo o campo, e tutto il codice che lo usava smette di compilare o si comporta male. Questo è critico soprattutto nelle API pubbliche.

Errore n°3: confusione tra variabili locali e campi della classe.
A volte gli sviluppatori dimenticano che una variabile dichiarata dentro un metodo vive solo lì. I campi della classe invece sono accessibili in tutti i suoi metodi. Questo porta a errori poco chiari, soprattutto se i nomi delle variabili coincidono.

Errore n°4: ignorare private e protected.
Molti hanno paura di usare accesso limitato, temendo di non poter più accedere a ciò che serve. Ma l'incapsulamento serve proprio a questo — nascondere tutto il superfluo e mostrare solo ciò che davvero serve all'esterno.

2
Compito
C# SELF, livello 17, lezione 0
Bloccato
Controllo dell’accesso tramite metodi
Controllo dell’accesso tramite metodi
2
Compito
C# SELF, livello 17, lezione 0
Bloccato
Utilizzo dell'incapsulamento con verifica della correttezza dei dati
Utilizzo dell'incapsulamento con verifica della correttezza dei dati
Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION