CIAO! Dedichiamo la lezione di oggi all'incapsulamento e cominciamo subito con gli esempi :) Principi di incapsulamento - 1Qui hai un normale distributore di bibite . Ho una domanda per te: come funziona? Prova a dare una risposta dettagliata: da dove viene la tazzina, come viene mantenuta la temperatura interna, dove si trova il ghiaccio, come fa la macchina a sapere quale sciroppo aggiungere, ecc.? Probabilmente non hai risposte a queste domande. Abbastanza giusto, dal momento che non tutti usano tali macchine. Non sono così popolari al giorno d'oggi. Proviamo a fare un altro esempio. Qualcosa che usi sicuramente molte volte ogni giorno. Oh, ecco un'idea! Principi di incapsulamento - 2Raccontaci come funziona il motore di ricerca Googlelavori. Come cerca esattamente le informazioni relative alle parole che inserisci? Perché alcuni risultati sono classificati in alto e altri no? Anche se usi Google ogni giorno, è probabile che tu non lo sappia. Ma non importa. Non hai bisogno di sapere questo. Puoi inserire query in un motore di ricerca senza pensare a come funziona. Puoi comprare la soda da una macchina senza sapere come funziona. Puoi guidare un'auto senza capire come funziona un motore a combustione interna e senza conoscere affatto la fisica, anche a livello di scuola elementare. Tutto questo è possibile grazie a uno dei principi fondamentali della programmazione orientata agli oggetti: l'incapsulamento. Leggendo vari articoli sulla programmazione orientata agli oggetti (OOP), devi esserti imbattuto nel fatto che la programmazione coinvolge due concetti comuni: incapsulamento e nascondimento . E gli autori usano la parola "incapsulamento" per indicare una cosa e poi un'altra. Esploreremo entrambi i termini in modo da ottenere una comprensione completa. In programmazione, il significato originale di incapsulamento è l'aggregazione di dati, insieme ai metodi che operano su tali dati, in una singola unità (cioè una "capsula"). In Java, la classe è l'unità di incapsulamento. Una classe contiene sia dati (campi) che metodi per lavorare con questi dati.Principi di incapsulamento - 3Questo può sembrare l'approccio ovviamente corretto per te, ma in altri paradigmi di programmazione tutto è organizzato in modo diverso. Ad esempio, nella programmazione funzionale, i dati sono rigorosamente separati dalle operazioni su di essi. In OOP, i programmi sono costituiti da capsule, o classi, che consistono sia di dati che di funzioni per lavorare con quei dati. Ora parliamo di nascondersi . Com'è possibile che usiamo tutti i tipi di dispositivi complessi senza capire come sono organizzati o come funzionano? È semplice: i loro creatori ci hanno fornito un'interfaccia semplice e conveniente. Su un distributore di bevande gassate, l'interfaccia sono i pulsanti sul pannello. Premendo un pulsante, scegli la dimensione della tazza. Premendone un altro, scegli il gusto. Un terzo è responsabile dell'aggiunta di ghiaccio. E questo è tutto ciò che devi fare. L'organizzazione interna della macchina non ha importanza. Ciò che conta è che è progettato in modo tale da richiedere all'utente di premere tre pulsanti per ottenere la soda . Lo stesso vale per le automobili. Non importa cosa succede dentro. Ciò che conta è che quando premi il pedale destro, l'auto si muove in avanti, e quando premi il pedale sinistro, rallenta. Questo è ciò che significa nascondersi. Tutti gli "interni" di un programma sono nascosti all'utente. Per l'utente, queste informazioni superflue e non necessarie. L'utente ha bisogno del risultato finale, non del processo interno. Prendiamo Autocome esempio la classe:

public class Auto {

   public void go() {

       /* Some complicated things happen inside the car.
       As a result, it moves forward */
   }

   public void brake() {

       /* Some complicated things happen inside the car.
       As a result, it slows down. */
   }

   public static void main(String[] args) {

       Auto auto = new Auto();

       // From the user's perspective,

       // one pedal is pressed and the car accelerates.
       auto.gas();
      
       // The other is pressed, and the car slows down.
       auto.brake();
   }
}
Ecco come appare l'occultamento dell'implementazione in un programma Java. È proprio come nella vita reale: all'utente viene fornita un'interfaccia (metodi). Se l'utente ha bisogno di un'auto in un programma per eseguire un'azione, chiama semplicemente il metodo desiderato. Ciò che accade all'interno di questi metodi è superfluo. Ciò che conta è che tutto funzioni come dovrebbe. Qui stiamo parlando dell'occultamento dell'implementazione . Oltre a ciò, Java nasconde anche i dati . Ne abbiamo parlato nella lezione su getter e setter , ma rivedere il concetto non guasta. Ad esempio, abbiamo una Catclasse:

public class Cat {

   public String name;
   public int age;
   public int weight;

   public Cat(String name, int age, int weight) {
       this.name = name;
       this.age = age;
       this.weight = weight;
   }

   public Cat() {
   }

   public void sayMeow() {
       System.out.println("Meow!");
   }

  
}
Forse ricordi il problema con questa classe dall'ultima lezione? In caso contrario, ricordiamolo ora. Il problema è che i suoi dati (campi) sono aperti a tutti: un altro programmatore può facilmente creare un gatto senza nome con un peso di 0 e un'età di -1000 anni:

public static void main(String[] args) {

   Cat cat = new Cat();
   cat.name = "";
   cat.age = -1000;
   cat.weight = 0;

}
Forse puoi tenere d'occhio se uno dei tuoi colleghi ha creato oggetti con stato non valido, ma sarebbe molto meglio escludere anche la possibilità di creare tali "oggetti non validi". Principi di incapsulamento - 4I seguenti meccanismi ci aiutano a nascondere i dati:
  1. modificatori di accesso ( private , protected , package default )
  2. getter e setter
Ad esempio, possiamo mettere un segno di spunta lì per vedere se qualcuno sta cercando di assegnare un numero negativo all'età del gatto. Come abbiamo detto in precedenza, gli autori di vari articoli sull'incapsulamento a volte intendono combinare dati e metodi, o nasconderli, o entrambi (combinarli e nasconderli). Java ha entrambi i meccanismi (questo non è necessariamente vero per altri linguaggi OOP), quindi l'ultimo significato è il più corretto. L'incapsulamento ci offre diversi importanti vantaggi:
  1. Controllo sullo stato corretto di un oggetto. C'erano esempi di questo sopra. Un setter e il modificatore privato assicurano che il nostro programma non abbia gatti il ​​cui peso è 0.

  2. Facilità d'uso attraverso un'interfaccia. Solo i metodi vengono lasciati "esposti" al mondo esterno. La chiamata ai metodi è sufficiente per ottenere un risultato: non è assolutamente necessario approfondire i dettagli di come funzionano.

  3. Le modifiche al codice non influiscono sugli utenti. Apportiamo tutte le modifiche all'interno dei metodi. Ciò non riguarda l'utente del metodo: se il codice giusto era precedentemente "auto.gas()" per applicare il pedale dell'acceleratore, allora continuerà ad esserlo. Il fatto che abbiamo cambiato qualcosa all'interno del metodo gas() rimane invisibile all'utente: come prima, il chiamante riceve semplicemente il risultato desiderato.