Programmazione orientata agli oggetti: differenze tra le versioni

Contenuto cancellato Contenuto aggiunto
m + tl risorsa
BoTTone (discussione | contributi)
Riga 1:
{{w}}
{{risorsa|tipo=lezione|materia1=Programmazione orientata agli oggetti}}
La '''programmazione orientata agli oggetti''' ('''OOP''', '''O'''bject '''O'''riented '''P'''rogramming) è un [[w:paradigma di programmazione|paradigma di programmazione]], che prevede di raggruppare in un'unica entità (la [[w:classe (informatica)|classe]]) sia le [[w:struttura dati|strutture dati]] che le [[w:funzione (informatica)|procedure]] che operano su di esse, creando per l'appunto un "[[w:oggetto (informatica)|oggetto]]" software dotato di proprietà (dati) e metodi ([[w:funzione (informatica)|procedure]]) che operano sui dati dell'oggetto stesso.
 
La [[w:modularizzazione|modularizzazione]] di un programma viene realizzata progettando e realizzando il codice sotto forma di classi che interagiscono tra di loro. Un programma ideale, realizzato applicando i criteri dell'OOP, sarebbe completamente costituito da oggetti software ('''istanze''' di classi) che interagiscono gli uni con gli altri.
 
La programmazione orientata agli oggetti è particolarmente adatta a realizzare [[w:GUI|interfacce grafiche]].
 
==Storia==
Il concetto di '''classe''' può essere considerato l'erede del [[w:tipo di dato astratto|tipo di dato astratto]], una tendenza che si è sviluppata all'interno del paradigma della [[w:programmazione procedurale|programmazione procedurale]], secondo la quale un [[w:Modulo (programmazione)|modulo]] dovrebbe implementare un [[w:tipo di dato|tipo di dato]] definito dall'utente, con cui si possa interagire solo attraverso una [[w:interfaccia|interfaccia]] ben definita, che nasconda agli altri moduli i dettagli dell'implementazione, in modo che sia possibile modificarli contenendo gli effetti della modifica sul resto del programma.
La classe può essere vista come il costrutto che permette di realizzare questa astrazione con un supporto strutturato da parte del linguaggio.
 
Il primo linguaggio di programmazione orientato agli oggetti fu il [[w:Simula|Simula]] ([[w:1967|1967]]), seguito negli [[w:Anni 1970|anni '70]] da [[w:Smalltalk|Smalltalk]] e da varie estensioni del [[w:Lisp|Lisp]]. Negli [[w:Anni 1980|anni '80]] sono state create estensioni orientate ad oggetti del linguaggio [[w:C (linguaggio)|C]] ([[w:C++|C++]], [[w:Objective C|Objective C]], e altri), e di altri linguaggi ([[w:Object Pascal|Object Pascal]]). Negli [[w:Anni 1990|anni '90]] è diventato il paradigma dominante, per cui gran parte dei linguaggi di programmazione erano o nativamente orientati agli oggetti o avevano una estensione in tal senso.
Oggi i linguaggi più usati tra quelli che supportano solo il paradigma di programmazione orientata agli oggetti sono Smalltalk ed [[w:Eiffel (linguaggio)|Eiffel]]. Tuttavia sono linguaggi in generale poco usati.
I linguaggi più usati sono invece quelli che supportano ''anche'' il paradigma di programmazione orientata agli oggetti, come [[w:C++|C++]], [[w:Java (linguaggio)|Java]], [[w:Delphi|Delphi]], [[w:Python|Python]], [[w:C sharp|C#]], [[w:Visual Basic .NET|Visual Basic .NET]], [[w:Perl|Perl]].
 
Un linguaggio di programmazione per poter essere definito ''ad oggetti'' deve possedere le tre proprietà seguenti : Incapsulamento, Ereditarietà e Polimorfismo (''vedi sotto'').
Riga 21:
Le [[w:classe (informatica)|classi]] sono uno strumento per costruire [[w:struttura dati|strutture dati]] che contengano non solo dati ma anche il codice per gestirli.
 
Come tutti i costrutti che permettono di definire le strutture dati, una classe definisce un nuovo [[w:tipo di dato|tipo di dato]].
 
I membri di una classe sono dati (esattamente come i membri di un [[w:Struttura dati#record o struct|record]]), chiamati '''attributi''', e '''metodi''', ovvero [[w:funzione (informatica)|procedure]], che operano su un oggetto.
 
Dal punto di vista matematico, una classe definisce un [[w:insieme|insieme]] in modo intensivo, ovvero definendone le caratteristiche invece che elencandone gli elementi. Se l'accesso agli attributi è ristretto ai soli membri della classe, le caratteristiche dell'insieme possono includere vincoli sui possibili valori che la [[w:tupla|tupla]] degli attributi può o non può assumere, e anche sulle possibili transizioni tra questi stati. Un oggetto può quindi essere visto come una [[w:macchina a stati finiti|macchina a stati finiti]].
 
Una classe può dichiarare riservate una parte delle sue proprietà e/o dei suoi metodi, e riservarne l'uso a sé stesso e/o a particolari tipi di oggetti a lui correlati.
Riga 33:
Un [[w:oggetto (informatica)|oggetto]] è una '''istanza''' di una classe. Un oggetto occupa memoria, la sua classe definisce come sono organizzati i dati in questa memoria.
 
Ogni oggetto possiede tutti gli [[w:attributi|attributi]] definiti nella classe, ed essi hanno un valore, che può mutare durante l'esecuzione del programma come quello di qualsiasi [[w:variabile (informatica)|variabile]].
Il paradigma OOP suggerisce un principio noto come [[w:information hiding|information hiding]] che indica che si debba accedere agli attributi dell'istanza solo tramite metodi invocati su quello stesso oggetto.
 
Sintatticamente, i metodi di una classe vengono invocati "su" un particolare oggetto, e ricevono come parametro implicito l'oggetto su cui sono stati invocati.
Questo parametro normalmente può essere referenziato esplicitamente; per esempio, a tale scopo in [[w:C++|C++]], in [[w:Linguaggio di programmazione Java|Java]], e in [[w:C_sharp|C#]] si usa la parola chiave '''this''', mentre in [[w:Smalltalk|Smalltalk]], in [[w:Objective_C|Objective-C]], [[w:Python|Python]] e in [[w:Ruby|Ruby]] si usa la parola-chiave '''self'''.
 
Gli oggetti effettivamente creati sono membri dell'insieme definito dalla loro classe.
Riga 61:
Se un oggetto di una sottoclasse può essere utilizzato al posto di un'istanza della superclasse, il tipo della classe derivata è detto '''sottotipo'''. Questo richiede che tutti i metodi della superclasse siano presenti nella sottoclasse, e che le signature siano compatibili. Di conseguenza, una sottoclasse che voglia definire un sottotipo può ridefinire i metodi della superclasse, ma non può eliminarli sintatticamente né modificare le loro signature.
 
In numerosi linguaggi, invece, una sottoclasse può decidere di eliminare o cambiare le proprietà di accesso ad un metodo, il che fa sì che l'operazione di subclassing non sia corrispondente a quella di subtyping. Alcuni linguaggi ad oggetti, in particolare [[w:Sather|Sather]], dividono esplicitamente a livello sintattico subclassing e subtyping.
 
In linguaggi con tipizzazione statica esplicita, una variabile dichiarata di tipo puntatore o riferimento ad una certa classe può fare riferimento ad oggetti sia del tipo per cui è dichiarata che di tipi da esso derivati. Il tipo effettivo della variabile viene quindi in generale definito a runtime, e può essere modificato durante l'esecuzione del programma.
Riga 72:
La possibilità che le classi derivate implementino in modo differente i metodi e le proprietà dei propri antenati rende possibile che gli oggetti appartenenti a delle sottoclassi di una stessa classe rispondano diversamente alle stesse istruzioni. Ad esempio in una gerarchia in cui le classi Cane e Gatto discendono dalla superclasse Animale potremmo avere il metodo cosaMangia() che restituisce la stringa "carne" se eseguito sulla classe Cane e "pesce" se eseguito sulla classe Gatto. I metodi che vengono ridefiniti in una sottoclasse sono detti "'''polimorfi'''", in quanto lo stesso metodo si comporta diversamente a seconda del tipo di oggetto su cui è invocato.
 
In linguaggi in cui le variabili non hanno tipo, come [[w:Ruby|Ruby]], [[w:Python|Python]] e [[w:Smalltalk|Smalltalk]] è possibile richiamare un qualsiasi metodo su di un qualsiasi oggetto, sebbene ciò comporti la possibilità di errori a run-time, che in particolare sorgono quando l'oggetto non dispone del metodo che si cerca di invocare.
Tali errori sono eliminabili da linguaggi puramente statici, in quanto essi vengono "scovati" già a compile-time.
 
Riga 84:
Per ritornare all'esempio di poco fa, supponiamo che un "aereo" debba affrontare procedure per l'arrivo e la partenza molto più complesse di un normale camion, come in effetti è: allora le procedure ''arrivo()'' e ''partenza()'' devono essere cambiate rispetto a quelle della classe base "mezzoditrasporto". Quindi provvediamo a ridefinirle nella classe "aereo" in modo che facciano quello che è necessario (polimorfismo): a questo punto, dalla nostra lista di mezzi possiamo prendere qualsiasi mezzo e chiamare ''arrivo()'' o ''partenza()'' senza doverci più preoccupare di che cos'è l'oggetto che stiamo maneggiando: che sia un mezzo normale o un aereo, si comporterà rispondendo alla stessa chiamata sempre nel modo giusto.
 
Il ''binding dinamico'' è supportato dai più diffusi linguaggi di programmazione ad oggetti come il [[w:Java (linguaggio)|Java]] o il [[w:C++|C++]]. C'è però da sottolineare che in Java il ''binding dinamico'' è implicitamente usato come comportamento di default nelle classi polimorfe, mentre il C++ per default non usa il ''binding dinamico'' e se lo si vuole utilizzare bisogna inserire la keyword '''virtual''' nella signature del metodo interessato.
 
Il supporto runtime di una chiamata di metodo polimorfa richiede che ad una variabile polimorfa venga associato un metadato implicito che contiene il tipo del dato contenuto nella variabile in un dato momento, oppure la tabella delle funzioni polimorfe.
Riga 91:
 
==Problemi dei linguaggi OOP==
Un linguaggio OOP può soffrire di problemi di efficienza se l'approccio OOP viene applicato a tutto indiscriminatamente, come avviene nel linguaggio [[w:Smalltalk|Smalltalk]] che utilizza gli oggetti anche per i tipi primitivi.
Un approccio che per alcuni appare più pratico e realista è quello adottato da linguaggi come [[w:Linguaggio di programmazione Java|Java]] e [[w:C++|C++]] che limitano la creazione di oggetti alle sole entità che il programmatore decide di dichiarare come tali più eventualmente una serie di oggetti predefiniti, per lo più riguardanti il sistema. In questo modo tali linguaggi restano efficienti, ma l'uso degli oggetti creati richiede più attenzione e più disciplina.
Non esistono al momento dati validi che permettano di dimostrare con certezza che uno dei due approcci sia intrinsecamente migliore dell'altro.
 
Inoltre il fatto di ridefinire i metodi ereditati dalle classi base può portare a introdurre errori nel programma se per caso questi sono usati all'interno della classe base stessa (il noto [[w:problema della classe base fragile|problema della classe base fragile]]).
 
== Collegamenti esterni ==
Riga 101:
*[http://www.python.org Python], un potente linguaggio ad oggetti.
 
[[w:Categoria:Linguaggi di programmazione|Categoria:Linguaggi di programmazione]]