Contenuto principale
Programmazione
Corso: Programmazione > Unità 1
Lesson 16: Programmazione Orientata agli OggettiRipasso: Programmazione Orientata agli Oggetti
Questo è un ripasso di quanto abbiamo imparato in questo tutorial sulla programmazione orientata agli oggetti.
Quando creiamo programmi, spesso scopriamo che vogliamo creare molti oggetti differenti che condividono simili proprietà - come ad esempio molti gatti che hanno il colore del pelo leggermente diverso o una dimensione leggermente diversa, con etichette e posizioni differenti. Vogliamo poter dire "questo è generalmente l'aspetto di un gatto" e poi dire "creiamo questo specifico gatto e poi quest'altro gatto, che saranno simili per certi versi ma anche diversi per altri". In quel caso, vogliamo usare la progettazione orientata agli oggetti per definire tipologie di oggetti e creare nuovi esempi di quegli oggetti.
Per definire una tipologia di oggetto in JavaScript, per prima cosa dobbiamo definire una "funzione costruttrice". Questa è la funzione che useremo ogniqualvolta vorremo creare un nuovo esempio di quella tipologia di oggetto. Ecco una funzione costruttrice per la tipologia di oggetto
Libro
:var Book = function(title, author, numPages) {
this.title = title;
this.author = author;
this.numPages = numPages;
this.currentPage = 0;
};
La funzione accetta argomenti per gli aspetti che differiscono in ciascun libro: titolo, autore e numero di pagine. Poi imposta le proprietà iniziali dell'oggetto in base a questi argomenti, usando la keyword
this
. Quando utilizziamo this
in un oggetto, ci stiamo riferendo all'istanza corrente dell'oggetto, riferendoci all'oggetto stesso. Dobbiamo salvare le proprietà in this
per essere sicuri di poterle richiamare dopo.Per creare un'istanza di un oggetto
Book
, dichiariamo una nuova variabile per contenerlo, poi usiamo la keyword new
, seguita dal nome della funzione costruttore, e gli passiamo gli argomenti che il costruttore si aspetta:var book = new Book("Robot Dreams", "Isaac Asimov", 320);
Possiamo quindi accedere a qualsiasi proprietà che abbiamo memorizzato nell'oggetto utilizzando la notazione puntata:
println("I loved reading " + book.title); // I loved reading Robot Dreams
println(book.author + " is my fav author"); // "Isaac Asimov" is my fav author
Lasciamo un attimo da parte questo, e vediamo cosa succederebbe se non impostassimo correttamente la nostra funzione costruttore:
var Book = function(title, author, numPages) {
};
var book = new Book("Little Brother", "Cory Doctorow", 380);
println("I loved reading " + book.title); // I loved reading undefined
println(book.author + " is my fav author"); // undefined is my favorite author
Se passiamo gli argomenti alla funzione costruttore ma non li salviamo esplicitamente in
this
, allora non potremo recuperarli in futuro! L'oggetto si dimenticherà di tutti gli argomenti.Quando definiamo i tipi di oggetti, spesso vogliamo associarli alle proprietà e ai comportamenti: per esempio, tutti i nostri oggetti cat dovrebbero essere in grado di meow() e eat(). Quindi dobbiamo poter attaccare delle funzioni alle definizioni dei nostri tipi di oggetti e possiamo farlo definendoli tramite il cosiddetto object prototype:
Book.prototype.readItAll = function() {
this.currentPage = this.numPages;
println("You read " + this.numPages + " pages!");
};
È simile a come definiremmo normalmente una funzione, tranne per il fatto che la attacchiamo al prototipo
Book
invece di definirla solo globalmente. È così che JavaScript sa che questa è una funzione che può essere chiamata in ogni oggetto Book
, e che questa funzione dovrebbe avere accesso al this
del libro su cui è chiamata.Possiamo quindi chiamare la funzione (che chiamiamo metodo, dato che è attaccata a un oggetto) in questo modo:
var book = new Book("Animal Farm", "George Orwell", 112);
book.readItAll(); // You read 112 pages!
Ricorda: l'obiettivo del design orientato agli oggetti è rendere più facile per noi creare più oggetti correlati (istanze di un oggetto). Vediamolo con il codice:
var pirate = new Book("Pirate Cinema", "Cory Doctorow", 384);
var giver = new Book("The Giver", "Lois Lowry", 179);
var tuck = new Book("Tuck Everlasting", "Natalie Babbit", 144);
pirate.readItAll(); // You read 384 pages!
giver.readItAll(); // You read 179 pages!
tuck.readItAll(); // You read 144 pages!
Questo codice ci dà tre libri simili: hanno tutti gli stessi tipi di proprietà e comportamenti, ma ne hanno anche di diversi. Bello!
Se pensi al mondo reale, gatti e cani sono diversi tipi di oggetti, quindi probabilmente vuoi creare diversi tipi di oggetti se vuoi programmare
Gatto
e Cane
. Un gatto sa miagolare()
, mentre un cane sa abbaiare()
. Ma sono anche simili: entrambi possono mangiare()
, entrambi hanno un'età
, una data di nascita
, e una di morte
. Sono entrambi mammiferi, e questo vuol dire che hanno molto in comune, anche se sono così diversi.In questo caso, vogliamo usare l'idea di ereditarietà degli oggetti. Un tipo di oggetto può ereditare proprietà e comportamenti da un tipo di oggetto genitore, ma poi avrà anche le sue particolarità. Ciascun
Gatto
e Cane
eredita le caratteristiche di Mammifero
, quindi non dovranno inventarsi da zero un'azione come mangiare()
. Come si fa questo in JavaScript?Torniamo al nostro esempio del libro e diciamo che
Book
è il tipo di oggetto "genitore", e vogliamo creare due tipi di oggetti che ereditano da esso: Paperback
e EBook
.Un paperback è un libro tascabile che ha una principale differenza rispetto a un comune libro, almeno nel nostro programma: ha un'immagine di copertina. Quindi il nostro costruttore deve prendere quattro argomenti per questa informazione aggiuntiva:
var PaperBack = function(title, author, numPages, cover) {
// ...
}
Ma non vogliamo dover fare di nuovo tutto il lavoro che abbiamo fatto nel costruttore
Book
per ricordare questi primi tre argomenti. Vogliamo approfittare del fatto che il codice sarebbe identico. Quindi possiamo chiamare il costruttore Book
dal costruttore PaperBack
e passargli questi argomenti:var PaperBack = function(title, author, numPages, cover) {
Book.call(this, title, author, numPages);
// ...
};
Dobbiamo comunque salvare la proprietà
cover
nell'oggetto, quindi ci serve un'altra riga:var PaperBack = function(title, author, numPages, cover) {
Book.call(this, title, author, numPages);
this.cover = cover;
};
Ora abbiamo un costruttore per il nostro
PaperBack
, che ci aiuta a condividere le stesse proprietà di Book
, ma vogliamo anche che il nostro PaperBack
erediti i suoi metodi. Ecco come fare, dicendo al programma che il prototipo PaperBack
deve essere basato sul prototipo Book
:PaperBack.prototype = Object.create(Book.prototype);
Potremmo anche voler collegare dei comportamenti particolari solo per paperback, come poter bruciare, e possiamo farlo definendo le funzioni nel prototipo, dopo la riga qui sopra:
PaperBack.prototype.burn = function() {
println("Omg, you burnt all " + this.numPages + " pages");
this.numPages = 0;
};
E ora possiamo creare un nuovo libro paperback, leggerlo tutto e bruciarlo!
var calvin = new PaperBack("The Essential Calvin & Hobbes", "Bill Watterson", 256, "http://ecx.images-amazon.com/images/I/61M41hxr0zL.jpg");
calvin.readItAll(); // You read 256 pages!
calvin.burn(); // Omg, you burnt all 256 pages!
(Beh, non lo bruceremo davvero, perché è un libro fantastico, ma forse lo faremmo se fossimo bloccati in un deserto di ghiaccio e volessimo disperatamente un modo per scaldarci per non morire.)
E ora sai come possiamo usare i principi di progettazione orientata agli oggetti in JavaScript per creare dati più complessi per i tuoi programmi e strutturare meglio il mondo dei tuoi programmi.
Vuoi unirti alla conversazione?
- nella sfida dei fiori la variabile amount dove è dichiarata?(1 voto)