Come spiegare i concetti di programmazione orientata agli oggetti a un bambino di 6 anni

Hai notato come le stesse domande cliché vengono sempre poste ai colloqui di lavoro - più e più volte?

Sono sicuro che sai cosa intendo.

Per esempio:

Dove ti vedi tra cinque anni?

o, peggio ancora:

Quale consideri la tua più grande debolezza?

Uff ... dammi una pausa. Considero la risposta a questa domanda una grande debolezza! Comunque, non è il mio punto.

Per quanto banali possano essere domande come queste, sono importanti perché danno indizi su di te. Il tuo stato d'animo attuale, il tuo atteggiamento, la tua prospettiva.

Quando rispondi, dovresti stare attento, poiché potresti rivelare qualcosa di cui in seguito ti pentirai.

Oggi voglio parlare di un tipo di domanda simile nel mondo della programmazione:

Quali sono i principi fondamentali della programmazione orientata agli oggetti?

Sono stato su entrambi i lati di questa domanda. È uno di quegli argomenti che vengono posti così spesso che non puoi permetterti di non sapere.

Gli sviluppatori junior e entry-level di solito devono rispondere. Perché è un modo semplice per l'intervistatore di dire tre cose:

  1. Il candidato si è preparato per questo colloquio?

    Punti bonus se senti immediatamente una risposta: mostra un approccio serio.

  2. Il candidato ha superato la fase del tutorial?

    La comprensione dei principi della programmazione orientata agli oggetti (OOP) mostra che sei andato oltre il copia e incolla dai tutorial: vedi già le cose da una prospettiva più elevata.

  3. La comprensione del candidato è profonda o superficiale?

    Il livello di competenza su questa domanda spesso è uguale al livello di competenza sulla maggior parte delle altre materie . Fidati di me.

I quattro principi della programmazione orientata agli oggetti sono incapsulamento , astrazione , ereditarietà ,e polimorfismo .

Queste parole possono sembrare spaventose per uno sviluppatore junior. E le spiegazioni complesse ed eccessivamente lunghe in Wikipedia a volte raddoppiano la confusione.

Ecco perché voglio dare una spiegazione semplice, breve e chiara per ciascuno di questi concetti. Può sembrare qualcosa che spieghi a un bambino, ma mi piacerebbe davvero sentire queste risposte quando conduco un'intervista.

Incapsulamento

Diciamo che abbiamo un programma. Ha pochi oggetti logicamente differenti che comunicano tra loro - secondo le regole definite nel programma.

L'incapsulamento si ottiene quando ogni oggetto mantiene il proprio stato privato , all'interno di una classe. Altri oggetti non hanno accesso diretto a questo stato. Possono invece chiamare solo un elenco di funzioni pubbliche, chiamate metodi.

Quindi, l'oggetto gestisce il proprio stato tramite metodi e nessun'altra classe può toccarlo se non esplicitamente consentito. Se vuoi comunicare con l'oggetto, dovresti usare i metodi forniti. Ma (per impostazione predefinita), non puoi modificare lo stato.

Diciamo che stiamo costruendo un piccolo gioco di Sims. Ci sono persone e c'è un gatto. Comunicano tra loro. Vogliamo applicare l'incapsulamento, quindi incapsuliamo tutta la logica "cat" in un fileCatclasse. Potrebbe assomigliare a questo:

Qui lo "stato" del gatto sono le variabili privatemood , hungrye energy. Ha anche un metodo privato meow(). Può chiamarlo quando vuole, le altre classi non possono dire al gatto quando miagolare.

Che cosa possono fare è definito nei metodi pubblicisleep() , play()e feed(). Ognuno di loro modifica in qualche modo lo stato interno e può invocare meow(). Così, viene stabilito il legame tra lo stato privato e metodi pubblici.

Questo è l'incapsulamento.

Astrazione

L'astrazione può essere pensata come un'estensione naturale dell'incapsulamento.

Nella progettazione orientata agli oggetti, i programmi sono spesso estremamente grandi. E oggetti separati comunicano molto tra loro. Quindi mantenere una base di codice di grandi dimensioni come questa per anni, con modifiche lungo il percorso, è difficile.

L'astrazione è un concetto che mira ad alleviare questo problema.

Applicare l'astrazione significa che ogni oggetto dovrebbe esporre solo un meccanismo di alto livello per usarlo.

Questo meccanismo dovrebbe nascondere i dettagli di implementazione interna. Dovrebbe rivelare solo le operazioni rilevanti per gli altri oggetti.

Pensa: una macchina da caffè. Fa un sacco di cose e fa rumori strani sotto il cofano. Ma tutto quello che devi fare è mettere il caffè e premere un pulsante.

Preferibilmente, questo meccanismo dovrebbe essere facile da usare e dovrebbe cambiare raramente nel tempo. Consideralo come un piccolo insieme di metodi pubblici che qualsiasi altra classe può chiamare senza "sapere" come funzionano.

Un altro esempio reale di astrazione?

Pensa a come usi il tuo telefono:

Si interagisce con il telefono utilizzando solo pochi pulsanti. Cosa sta succedendo sotto il cofano? Non devi saperlo: i dettagli di implementazione sono nascosti. Hai solo bisogno di conoscere una breve serie di azioni.

Le modifiche all'implementazione, ad esempio un aggiornamento software, influiscono raramente sull'astrazione utilizzata.

Eredità

OK, abbiamo visto come l'incapsulamento e l'astrazione possono aiutarci a sviluppare e mantenere una grande base di codice.

Ma sai qual è un altro problema comune nella progettazione OOP?

Gli oggetti sono spesso molto simili. Condividono una logica comune. Ma non sono del tutto la stessa cosa. Uffa ...

Allora come riutilizziamo la logica comune ed estraiamo la logica univoca in una classe separata? Un modo per ottenere questo risultato è l'eredità.

Significa che crei una classe (figlia) derivando da un'altra classe (genitore). In questo modo, formiamo una gerarchia.

La classe figlia riutilizza tutti i campi e i metodi della classe genitore (parte comune) e può implementarne uno proprio (parte univoca).

Per esempio:

Se il nostro programma ha bisogno di gestire insegnanti pubblici e privati, ma anche altri tipi di persone come gli studenti, possiamo implementare questa gerarchia di classi.

In questo modo, ogni classe aggiunge solo ciò che è necessario, riutilizzando la logica comune con le classi padre.

Polimorfismo

Siamo arrivati ​​alla parola più complessa! Il polimorfismo significa "molte forme" in greco.

Quindi conosciamo già il potere dell'eredità e lo usiamo felicemente. Ma arriva questo problema.

Supponiamo di avere una classe genitore e alcune classi figlie che ereditano da essa. A volte si desidera utilizzare una raccolta, ad esempio un elenco, che contiene un mix di tutte queste classi. Oppure abbiamo un metodo implementato per la classe genitore, ma vorremmo usarlo anche per i bambini.

Questo può essere risolto usando il polimorfismo.

In poche parole, il polimorfismo offre un modo per utilizzare una classe esattamente come la sua genitrice, quindi non c'è confusione con i tipi di miscelazione.Ma ogni classe figlia mantiene i propri metodi così come sono.

Ciò accade tipicamente definendo un'interfaccia (genitore) da riutilizzare. Delinea una serie di metodi comuni. Quindi, ogni classe figlia implementa la propria versione di questi metodi.

Ogni volta che una raccolta (come una lista) o un metodo si aspetta un'istanza del genitore (dove sono descritti metodi comuni), il linguaggio si occupa di valutare la corretta implementazione del metodo comune, indipendentemente da quale figlio viene passato.

Dai un'occhiata a uno schizzo dell'implementazione delle figure geometriche. Riutilizzano un'interfaccia comune per il calcolo della superficie e del perimetro:

Avendo queste tre figure che ereditano il genitore Figure Interfaceconsente di creare un elenco di misto triangles, circlese rectangles. E trattali come lo stesso tipo di oggetto.

Quindi, se questo elenco tenta di calcolare la superficie di un elemento, viene trovato ed eseguito il metodo corretto. Se l'elemento è un triangolo, il triangoloCalculateSurface()è chiamato. Se è un cerchio, allora quello di CirlceCalculateSurface()è chiamato. E così via.

Se hai una funzione che opera con una figura utilizzando il suo parametro, non devi definirla tre volte: una per un triangolo, un cerchio e un rettangolo.

Puoi definirlo una volta e accettare un file Figurecome argomento. Sia che passi un triangolo, un cerchio o un rettangolo, purché implementino CalculateParamter(), il loro tipo non ha importanza.

Spero che questo abbia aiutato. Puoi utilizzare direttamente queste stesse identiche spiegazioni durante i colloqui di lavoro.

Se trovi qualcosa di ancora difficile da capire, non esitare a chiedere nei commenti qui sotto.

Qual è il prossimo?

Essere pronti a rispondere a una delle classiche domande dell'intervista di tutti i tempi è fantastico, ma a volte non vieni mai chiamato per un colloquio.

Successivamente, mi concentrerò su ciò che i datori di lavoro vogliono vedere in uno sviluppatore junior e su come distinguersi dalla massa durante la ricerca di lavoro.

Rimanete sintonizzati.