39 OOP

Il paradigma dell’ Object Oriented Programming nasce come risposta alla sempre più crescente complessità del codice, portando numerose migliorie.

Ecco uno schema che differenzia il modello di programmazione OOP dalla programmazione proceduraleimperativa vista fino ad ora:

schema OOP e procedurale

Ogni funzione creata nella parte di sinistra è fine a se stessa e avendo per esempio numerose linee di codice, dovremmo fare molta attenzione a tenere tutto sotto controllo, perchè non abbiamo una delineazione ben precisa del nostro oggetto. Pensiamo ad un oggetto clienti, con le funzioni, dovendo implementare eventuali nuove caratteristiche dovremmo modificare le funzioni interessate con notevoli rischi di errore.

Con l’OOP avremmo creato l’oggetto clienti estendendolo con nuove funzionalità lasciando intatta la struttura dell’oggetto originale.

In OOP si definisce un oggetto nei termini dei dati che lo caratterizzano, cercando di mantenerli il più possibile nascosti al di fuori dell’oggetto e delle funzioni chiamati metodi, per lavorare con questi dati, richiamabili per lavorare su quelli e altri dati. Sostanzialmente l’oggetto è una capsula (tipo le graffe delle funzioni) che mantiene uniti dati e metodi che sono tra loro correlati.

Riutilizzo codice OOP

Se dobbiamo estendere un oggetto, per esempio bicicletta, con delle particolarità, col procedurale devo ricopiarmi il codice precedentemente scritto e aggiungerne ulteriore. Se devo fare una modifica, dovrò riportarla su tutto il codice copiato. Se ho un errore lo ritroverò su tutto il codice, oltre ad avere numerose linee di codice ripetuto. Con l’OOP, grazie al concetto di ereditarietà,  avrò l’oggetto biciclettai stanziato solo una volta, mentre la mountain bike prenderà già tutte le caratteristiche della bicicletta aggiungendo quelle specifiche che caratterizzano.

In altri linguaggi come il C++, il Java, il C# prima di definire un oggetto devo definirne la classe che ne determina l’incapsulamento dell’oggetto:

OOP in altri linguaggi: classe

Una volta creata la classe non abbiamo definito ancora l’oggetto, che dovrà essere stanziato con quella classe ed ereditarne le proprietà.

In JS la creazione, dichiarazione o istanza di un oggetto è molto più semplice:

let nome = {};

Ho creato un nuovo oggetto vuoto chiamato nome, l’incapsulamento di questo oggetto è quello racchiuso tra parentesi graffe.

Creiamo un oggetto punto che avrà come proprietà le sue coordinate cartesiane ( x e y )

let punto = {};
writeln(punto);

Eseguendo il codice il browser mi mostra che ho creato un oggetto:

[object Object]

Negli altri linguaggi sopra menzionati dovrei creare anche una classe vuota e per aggiungere le proprietà x, y andare ad aggiungerle nella classe, in js invece le specifico al volo:

let punto = {};
writeln(punto);

punto.x = 100;
punto.y = 200;

writeln(punto.x + punto.y);

In js non essendoci le classi (almeno prima di ES6) c’è un nome che descrive questo modello di oggetto: per prototipazione  che ci permette di definire un prototipo o modello che ci permette di creare nuovi oggetti senza partire da zero.

3 modi per creare un oggetto

  1. Creo un oggetto cliente con proprietà nome e cognome
    let cliente = { cognome:"Rossi", nome:"Mario" };

    Ecco la vera natura interna per js, una collezione di coppie chiave / valore cioè un identificatore (cognome e nome) due punti, un’espressione che ne determina il valore (Rossi e Mario).

  2. Creiamo lo stesso oggetto cliente senza proprietà, in altre parole un oggetto vuoto
    let cliente = {};

    aggiungiamo le proprietà successivamente

    cliente.nome = "Mario";
    cliente.cognome="Rossi";
  3. Sfruttiamo l’oggetto predefinito Object() e usiamo il costrutto new Object

    let cliente = new Object();

    aggiungiamo le proprietà successivamente come fatto prima

    cliente.nome = "Mario";
    cliente.cognome="Rossi";

Richiamare le proprietà degli oggetti

Dato il seguente oggetto:

let gatto = { nome:"Ciccio", razza:"europeo", mantello:"tigrato" };

Esistono 2 modi per richiamare le proprietà di un oggetto,

il primo ha una sintassi simile agli array, è da usare quando una proprietà inizia con un numero

document.write(gatto["razza"]);

Il secondo è molto più agile ed è da preferirsi a priori

document.write(gatto.mantello);

Aggiungere i metodi

Ecco come si aggiungono i metodi:

let cliente = { cognome:"Rossi", nome:"Mario",
                Nominativo: function() { return cognome + " " + nome } };

writeln(cliente.Nominativo);

In questo caso writeln non stamperà il risultato del metodo Nominativo, ovvero Rossi Mario, ma proprio il valore del metodo

function () { return cognome + " " + nome }

Per eseguire il metodo dobbiamo aggiungere le parentesi tonde per identificarlo

writeln(cliente.Nominativo() );

a questo punto eseguendo il codice riceveremo un errore di variabile cognome not defined.

Questo avviene perchè nel contesto di un oggetto, un metodo (o funzione) può riferirsi alle proprietà (o variabili) dell’oggetto stesso, solo utilizzando un puntatore all’oggetto stesso identificato con this :

let cliente = { cognome:"Rossi", nome:"Mario",
                Nominativo: function() { return this.cognome + " " + this.nome } };
writeln(cliente.Nominativo());

il this.cognome si riferisce a cliente.cognome.

Quindi quando si usa il this nel contesto di una funzione di un oggetto, il this punta all’oggetto stesso.