Skillbook Logo
foto profilo

Categoria: Tutorials


La geometria della tartaruga Pitagora: "Il piano cartesiano" - Lezione 1

Gino Visciano | Skill Factory - 16/01/2021 01:17:46 | in Tutorials

Benvenuti alla prima lezione, l'obiettivo di questa prima attività è quello d'introdurre il significato di geometria e di piano cartesiano.

Per spiegare questi due concetti astratti ci faremo aiutare da Pitagora, la tartaruga esperta di geometria che vi farà scoprire il mondo dei punti e delle figure geometriche.

Pitagora è una tartaruga che può essere programmata con il linguaggio Python che fa tutto quello che gli insegnate, per queste attività gli abbiamo spiegato la geometria analitica o geometria cartesiana, la scienza matematica che permette di misurare le figure geometriche disegnate su un piano cartesiano.

La parola geometria nasce dalla composizione di due parole geo="terra" e metria="misura" e significa "misurazione della terra", la possiamo definire la scienza matematica che studia la disposizione dei punti nello spazio che formano le figure.

Lo spazio è l'ambiente che vi circonda in cui si trovano tutte le cose che vedete e con cui vi relazionate tutti i giorni. 

Poiché lo spazio che ci circonda è troppo grande, al punto di sembrare infinito, in geometria per misurare le cose si usa uno spazio molto più piccolo: il "piano cartesiano".

Un piano cartesiano lo potete immaginare come una parte di spazio delimitata, di forma quadrata o rettangolare, divisa in quattro parti da due assi perpendicolari (ortogonali), che contiene i punti e le figure da misurare.

Il  nome cartesiano è riferito al  matematico francese Cartesio, nel 1637 fu uno dei primi ad utilizzarlo  per effettuare misure geometriche. 

L'asse verticale, indicato con la lettera Y, si chiama asse delle ordinate, mentre quello orizzontale, indicato con la lettera X, si chiama asse delle ascisse.

Il punto in cui i due assi s'incontrano (intersezione), si chiama origine e si indica con la lettera O.

I valori dell'asse delle ascisse X a sinistra dell'origine O sono negativi (-), quelli a destra invece sono positivi (+).

I valori dell'asse delle ordinate Y al di sopra dell'origine O sono positivi (+), quelli al di sotto invece sono negativi (-).

Per indicare la posizione di qualunque punto nel piano dovete usare sempre una coordinata X ed una Y, come indicato nell'immagine seguente:

Le coordinate che indicano l'origine O  sono (X=0, Y=0).

In questa prima versione la tartaruga Pitagora è stata programmata per indicare le coordinate X ed Y dei punti del piano su cui cliccate usando il puntatore  del mouse, come indica l'immagine seguente:

Per usare il programma dovete installare l'interprete Python, per il download del programma d'installazione cliccate qui.

Per leggere, modificare ed eseguire il programma pitagora_v1.py, vi suggerisco di usare l'IDE (Integrated Development Environment) Visual Studio Code, per il download del programma d'installazione cliccate qui.

Per maggiori informazioni su Python e Visual Studio Code, cliccate qui per scaricare la guida.

 

COME PROGRAMMARE LA TARTARUGA PITAGORA

1) Per utilizzare la tartaruga Pitagora in un programma Python, dovete importare il modulo turtle con il comando:

import turtle

2) Con i comandi seguenti potete impostare la  forma della tartaruga, il colore, le dimensioni e la velocità di spostamento:

turtle.shape("turtle")
turtle.color("green")
turtle.shapesize(stretch_wid=2, stretch_len=2, outline=None)
turtle.speed(3)

3) Per impostare la dimensione della tartaruga potete anche usare il comando:

turtle.turtlesize(2)

4) Le forme di tartarughe possono essere le seguenti: "arrow", "turtle", "circle", "square", "triangle", "classic".

5) Per nascondere la tartaruga Pitagora usate il comando:

turtle.hideturtle()

6) Per mostrare la tartaruga Pitagora usate il comando:

turtle.showturtle()

7) La tartaruga Pitagora può ruotare sia in senso orario, sia in senso antiorario, ad esempio:

# Ruota la tartaruga di 60° in senso orario
turtle.rigth(60)

# Ruota la tartaruga di 60° in senso antiorario
turtle.left(60)

Il comando seguente vi permette d'impostare la direzione iniziale della tartaruga Pitagora:

turtle.setheading(90)

8) La tartaruga Pitagora quando si muove sul piano può disegnare, i comandi seguenti vi permettono di impostare lo stato della penna:

# Non disegna
turtle.penup()

# Disegna
turtle.pendown()

# Imposta il colore della penna
turtle.pencolor("black")

# Imposta lo spessore della punta della penna
turtle.pensize(10)

Nell'esempio seguente la tartaruga Pitagora disegna un segmento di colore rosso:

import turtle
turtle.shape("turtle")
turtle.turtlesize(2)
turtle.left(60)
turtle.pencolor("red")
turtle.pensize(5)

# Sposta la tartaruga Pitagora in avanti alla posizione 100
turtle.forward(100)
# Si mette in ascolto per verificare se l'utente esegue operazioni
turtle.mainloop()

9) I comandi seguenti permettono di muovere la tartaruga Pitagora:

# Sposta la tartaruga in avanti della distanza indicata
turtle.forward(100)

# Sposta la tartaruga indietro della distanza indicata
turtle.back(50)

# Sposta la tartaruga alle coordinate X,Y indicate
turtle.goto(-100,50)

# Sposta la tartaruga a caso nella posizione (X=0, Y=0)
turtle.home()

10) La tartaruga Pitagora, può scrivere nella posizione del piano in cui si trova, con il comando seguente:

turtle.write('La geometria della tartaruga Pitagora',align='center',font=("Garamond", 12, "normal"))

Le informazioni che dovete fornire al comando sono le seguenti:

a) Testo da scrivere
b) Tipo di allineamento: "center", "left", "right"
c) Tipo di carattere di stampa, ad esempio: "Ariale"
d) Dimensione del testo
e) Aspetto: "normal", "italic", "bold"

11) Per disegnare un punto nella posizione del piano in cui si trova la tartaruga Pitagora, usare il comando:

turtle.dot(10,colore)

12) Per associare una funzione Python al  click del mouse usare il comando seguente:

# Esegue la funzione evento_mouse_click quando si clicca con il mouse
turtle.onscreenclick(evento_mouse_click)

13) Per associare una funzione Python ad un tasto premuto usare il comando seguente:

turtle.onkey(undo,"space")
# Ascolta quando viene premuto lo spazio ed esegue la funzione undo

turtle.listen()

COME VISUALIZZARE O COPIARE IL CODICE PYTHON DEL PROGRAMMA PITAGORA

Per visualizzare o copiare il codice Python del programma PITAGORAcliccate qui
Dopo la visualizzazione del codice Python, lo potete selezionare e copiare.
Se incollate il codice Python copiato in un nuovo file creato con Visual Studio Code lo potete salvare con il nome python_v1.py ed eseguire.

 

COME FARE IL DOWNLOAD DEL PROGRAMMA PITAGORA

1) Per eseguire il programma PITAGORA vi serve il file  pitagora_v1.py, per fare il download cliccate qui;
2) Dopo il download estrate dallo zip il file pitagora_v1.py;

 

COME ESEGUIRE IL PROGRAMMA PITAGORA

1) Se state lavorando con Windows  aprite esplora risorse, portatevi sotto la cartella dove si trova il file pitagora_v1.py ed eseguitelo con il doppio click;  
2) Per eseguire il programma da prompt dei comandi, portatevi sotto la cartella dove si trova il file pitagora_v1.py ed scrivete il comando:

python pitagora_v1.py

3) Per eseguire il programma da Visual Studio Code, aprite il file pitagora_v1.py premete il tasto desto del mouse e selezionate il comando Run Python File in Terminal:

 

 

COME DISEGNARE I PUNTI SUL PIANO CARTESIANO

Dopo l'avvio del programma, per disegnare i punti sul piano cartesiano, cliccate con il mouse in un punto qualsiasi, la tartaruga Pitagora disegnarà il punto e le sue coordinate nella posizione indicata.

Arrivederci alla prossima lezione!


Per far parte della nostra community registrati su www.skillbook.it.


T U T O R I A L S    S U G G E R I T I


EDUCATIONAL GAMING BOOK (EGB) "H2O"

Nell'era dello SMART LEARNING e di PYTHON i libri non si scrivono, ma si sviluppano, in questo modo chi studia, può sperimentare ed apprendere contemporaneamente; un libro con queste caratteristiche lo possiamo definire un  Educational Gaming Book (EGB).

"H2Oè un EGB che descrive tutte le caratteristiche dell'acqua, la sostanza formata da molecole di H2O, che attraverso il suo ciclo di vita garantisce la sopravvivenza di tutti gli esseri viventi del Pianeta

L'obiettivo dell'EGB è quello di far conoscere ai giovani le proprietà dell'acqua, sotto molti aspetti uniche, per sensibilizzarli a salvaguardare un bene comune raro, indispensabile per la vita


Per il DOWNLOAD di "H2Oclicca qui.

Share Button

Competenze per programmare

Gino Visciano | Skill Factory - 28/11/2020 19:47:49 | in Tutorials

La PLAYLIST "Competenze per programmare" è  una raccolta di lezioni pubblicate sul canale YOUTUBE  "Skill Factory channel"  rivolte ai giovani che devono acquisire le competenze fondamentali  per imparare a programmare.  Clicca qui per accedere alla PLAYLIST.

La PLAYLIST , di volta in volta, si arricchirà di nuove lezioni con nuovi contenuti che vi permetteranno di conoscere i linguaggi di programmazione più utilizzati dai programmatori che lavorono nelle aziende IT.

Per ricevere in tempo reale le notifiche delle nuove lezioni pubblicate, cliccate sul pulsante seguente per iscrivervi al canale.  Attenzione durante l'iscrizione non dimenticate di cliccare sulla campanella per richiedere l'invio delle notifiche dei video pubblicati.

In questa pagina verranno pubblicati tutti i programmi sviluppati durante le lezioni in modo da poterli scaricare e provare.
(Per motivi di sicurezza i programmi hanno tutti l'estensione txt, per poterli eseguire li dovete salvare e rinominare con l'estensione giusta.)


RISORSE PALYLIST "COMPETENZE PER PROGRAMMARE"

Contatore JavaScript
Contatore Python
Semaforo JavaScript
Semaforo bis JavaScript
Semaforo Python
Intervalli JavaScript
Condizioni JavaScript
Condizioni Python
Cicli nidificati JavaScript
Cicli nidificati Python
Vettore JavaScript
Vettore Python
Matrice JavaScript
Matrice Python
Tabellina JavaScript
Tabellina Python
Laboratorio_uno JavaScript
Laboratorio_uno Python

Laboratorio_due JavaScript
Laboratorio_due Python

 

Share Button

TypeScript - Lezione 7: Paradigma Object Oriented (seconda parte)

Gino Visciano | Skill Factory - 07/08/2020 22:54:12 | in Tutorials

Nella lezione precedente abbiamo introdotto il "Paradigma Object Oriented", descrivendo le seguenti proprietà di programmazione:

1) Incapsulamento;
2) Ereditarietà;
3) Polimorfismo dei metodi.

In questa lezione completiamo le proprietà di programmazione parlando di "Polimorfismo degli oggetti", la proprietà che ci permette di sfruttare le potenzialità offerte dall'Upcasting, successivamente vediamo le proprietà architetturali per creare applicazioni riusabili , scalabili e manutenibili.  

POLIMORFISMO DEGLI OGGETTI

Gli oggetti sono Polimorfi se sono simili, due oggetti possono diventare simili per ereditarietà oppure se implementano la stessa interfaccia.

Il Diagramma di classe seguente descrive un esempio di polimorfismo per erditarietà:

La classe Dirigente è la più specializzata, perché contiene maggiori responsabilità e caratteristiche, quindi è più dettagliata, mentre la classe Object è la più generica.

Tutti gli oggetti istanziati con uno dei tipi indicati nel diagramma sono simili, perché appartengono alla stessa gerarchia di ereditarietà.

Quando gli oggetti sono simili è possibile applicare l'upcasting, che permette di  assegnare ad una variabile di tipo  più generico il riferimento di un oggetto più dettagliato, come mostra l'esempio seguente:

var persona:Persona; // Variabile più generica di tipo Persona
persona=new Dipendente() // Upcasting. Il riferimento dell'oggetto di tipo Dipendente, più dettagliato, viene assegnato ad una variabile più generica di tpo Persona

L'Upcasting è utile  perché con questa tecnica è possibile passare alla stesso metodo oggetti di tipo diverso, purché simili tra loro, come mostra l'esempio seguente:

Esempio 1

 
class Persona{
    private id:number;
    private nome:string;
    private cognome:string;
    private dataDiNascita:Date;
    private luogoDiNascita:string;
    private sesso:string;
    public setId(id:number):void{
        this.id=id;
    }
    public getId():number{
        return this.id;
    }
    public setNome(nome:string):void{
        this.nome=nome;
    }
    public getNome():string{
        return this.nome;
    }
    public setCognome(cognome:string):void{
        this.cognome=cognome;
    }
    public getCognome(){
        return this.cognome;
    }
    public setDataDiNascita(dataDiNascita:Date):void{
        this.dataDiNascita=dataDiNascita;
    }
    public getDataDiNascita():Date{
        return this.dataDiNascita;
    }
    public setLuogDiNascita(luogoDiNascita:string):void{
        this.luogoDiNascita=luogoDiNascita;
    }
    public getLuogoDiNascita():string{
        return this.luogoDiNascita;
    }
    public setSesso(sesso:string):void{
        this.sesso=sesso;
    }
    public getSesso():string{
        return this.sesso;
    }
    public toString():string{
        let optionsIntl.DateTimeFormatOptions = {
            day: "numeric"month: "numeric"year: "numeric"
        };
 
           return this.id+","+this.nome+","+this.cognome+","+this.dataDiNascita.toLocaleDateString("en-GB"options)+","+this.luogoDiNascita+","+this.sesso;
    }
    public equals(obj:Object):boolean{
        if (this.toString()!=obj.toString()){
            return false;
        }
        return true;
    }
        // Sovraccarico del costruttore
        public constructor();
        public constructor(id:number,nome:string,cognome:string,dataDinascita:Date,luogoDiNascita:string,sesso:string);
        public constructor(id?:number,nome?:string,cognome?:string,dataDinascita?:Date,luogoDiNascita?:string,sesso?:string){
            this.id=id;
            this.nome=nome;
            this.cognome=cognome;
            this.dataDiNascita=dataDinascita;
            this.luogoDiNascita=luogoDiNascita;
            this.sesso=sesso;
        }    
}
 
class Dipendente extends Persona {
    private ruolo:string;
    private stipendio:number;
    public setRuolo(ruolo:string):void{
        this.ruolo=ruolo;
    }
    public getRuolo():string{
        return this.ruolo;
    }
    public setStipendio(stipendio:number):void{
        this.stipendio=stipendio;
    }
    public getStipendio():number{
        return this.stipendio;
    }
    public toString():string{
        return super.toString()+","+this.ruolo+","+this.stipendio;
    }
    public equals(obj:Object):boolean{
        if (this.toString()!=obj.toString()){
            return false;
        }
        return true;
    }
            // Sovraccarico del costruttore
            public constructor();
            public constructor(id:number,nome:string,cognome:string,dataDinascita:Date,luogoDiNascita:string,sesso:string,ruolo:string,stipendo:number);
            public constructor(id?:number,nome?:string,cognome?:string,dataDinascita?:Date,luogoDiNascita?:string,sesso?:string,ruolo?:string,stipendo?:number){
                super(id,nome,cognome,dataDinascita,luogoDiNascita,sesso); 
                this.ruolo=ruolo;
                this.stipendio=stipendo;
            }      
}
class Vista {
public stampa(persona:Persona){
    console.log(persona.toString())
    }    
public stampaScheda(persona:Persona){
    let optionsIntl.DateTimeFormatOptions = {
        day: "numeric"month: "numeric"year: "numeric"
    };
    console.log("Id:"+persona.getId());
    console.log("Nome:"+persona.getNome());
    console.log("Cognome:"+persona.getCognome());
    console.log("Data di nascita:"+persona.getDataDiNascita().toLocaleDateString("en-GB"options));
    console.log("Luogo di nascita:"+persona.getLuogoDiNascita());
    console.log("Sesso:"+persona.getSesso());
    // Se la variabile persona è un riferimento di tipo dipendente visualizza anche ruolo e stipendio
    if(persona instanceof Dipendente){
        console.log("Ruolo:"+persona.getRuolo());
        console.log("Stipendio:"+persona.getStipendio());
    }
    }
}
// Istanza di un oggetto di tipo Vista (view), per stampare gli oggetti simili di tipo Persona e Dipendente (model) 
var vista=new Vista();
// Istanzio due oggetti di tipo Persona (model)
var personaUno=new Persona();
var personaDue=new Persona(2,"Carla","Verdi",new Date("10/05/1992"),"Milano","F");
// Istanzio due oggetti di tipo Dipendente (model)
var dipendenteUno=new Dipendente();
var dipendenteDue=new Dipendente(4,"Paolo","Formisano",new Date("09/02/1970"),"Potenza","M","Commerciale",1800.00);
personaUno.setId(1);
personaUno.setNome("Roberta");
personaUno.setCognome("Bianchi");
personaUno.setDataDiNascita(new Date("09/07/2000"));
personaUno.setLuogDiNascita("Firenze");
personaUno.setSesso("F");
dipendenteUno.setId(3);
dipendenteUno.setNome("Michele");
dipendenteUno.setCognome("Rossi");
dipendenteUno.setDataDiNascita(new Date("08/03/1980"));
dipendenteUno.setLuogDiNascita("Torino");
dipendenteUno.setSesso("M");
dipendenteUno.setRuolo("Project Managaer");
dipendenteUno.setStipendio(1500.00);
console.log("------ Persone stampa orizzontale ------")
vista.stampa(personaUno);
console.log("---------------------------------------")
vista.stampa(personaDue);
console.log("\n------ Dipendenti stampa orizzontale ------")
vista.stampa(dipendenteUno);
console.log("--------------------------------------")
vista.stampa(dipendenteDue);
console.log("\n------ Persone stampa scheda ------")
vista.stampaScheda(personaUno);
console.log("--------------------------------")
vista.stampaScheda(personaDue);
console.log("\n------ Dipendenti stampa scheda ------")
vista.stampaScheda(dipendenteUno);
console.log("--------------------------------")
vista.stampaScheda(dipendenteDue);
 
---------------------------------------------------------------------------------------

------ Persone stampa orizzontale ------
1,Roberta,Bianchi,9/7/2000,Firenze,F
---------------------------------------
2,Carla,Verdi,10/5/1992,Milano,F

------ Dipendenti stampa orizzontale ------
3,Michele,Rossi,8/3/1980,Torino,M,Project Managaer,1500
--------------------------------------
4,Paolo,Formisano,9/2/1970,Potenza,M,Commerciale,1800

------ Persone stampa scheda ------
Id:1
Nome:Roberta
Cognome:Bianchi
Data di nascita:9/7/2000
Luogo di nascita:Firenze
Sesso:F
--------------------------------
Id:2
Nome:Carla
Cognome:Verdi
Data di nascita:10/5/1992
Luogo di nascita:Milano
Sesso:F

------ Dipendenti stampa scheda ------
Id:3
Nome:Michele
Cognome:Rossi
Data di nascita:8/3/1980
Luogo di nascita:Torino
Sesso:M
Ruolo:Project Managaer
Stipendio:1500
--------------------------------
Id:4
Nome:Paolo
Cognome:Formisano
Data di nascita:9/2/1970
Luogo di nascita:Potenza
Sesso:M
Ruolo:Commerciale
Stipendio:1800

 

 

Gli oggetti possono diventare simili, anche se implementano la stessa interfaccia, iDiagramma di classe seguente descrive un esempio di polimorfismo per interfaccia:
 

In questo caso l'Upcasting si può applicare utilizzando come tipo l'interfaccia, come mostra l'esempio seguente:

var cerchio:IFiguraGeometrica;
var rettangolo:IFiguraGeometrica;
cerchio=new Cerchio();
rettangolo=new Rettangolo(); 

Esempio 2

//geometria.ts
interface IFiguraGeometrica{
    getTipoFigura():string;
    getPerimetro():number;
    getArea():number;
}
 
class Cerchio implements IFiguraGeometrica{
    public constructor(private raggio:number){}
    public getTipoFigura():string{
        return "Cerchio";
    }
    public getPerimetro(): number {
        return 2*Math.PI*this.raggio;
    }
    public getArea(): number {
        return Math.pow(this.raggio,2)*Math.PI;
    }
}
 
class Quadrato implements IFiguraGeometrica{
    public constructor(private latoA:number){}
    public getTipoFigura():string{
        return "Quadrato";
    }
    public getPerimetro(): number {
        return 4*this.latoA;
    }
    public getArea(): number {
        return Math.pow(this.latoA,2);
    }
}
 
class Rettangolo implements IFiguraGeometrica{
    public constructor(private latoA:number,private latoB:number){}
    public getTipoFigura():string{
        return "Rettangolo";
    }
    public getPerimetro(): number {
        return (2*this.latoA)+(2*this.latoB);
    }
    public getArea(): number {
        return this.latoA*this.latoB;
    }
}
 
class Triangolo implements IFiguraGeometrica{
    public constructor(private latoA:number,private latoB:number,private latoC:number){}
    public getTipoFigura():string{
        return "Triangolo";
    }
    public getPerimetro(): number {
        return this.latoA+this.latoB+this.latoC;
    }
    public getArea(): number {
        let sp=this.getPerimetro()/2;
        let area=Math.sqrt(sp*(sp-this.latoA)*(sp-this.latoB)*(sp-this.latoC))
        return area;
    }
}
class Geometria {
    private figureGeometriche:IFiguraGeometrica[]=[]
    public add(figuraGeometrica:IFiguraGeometrica):void{
        this.figureGeometriche.push(figuraGeometrica);
    }
    public stampa(){
        this.figureGeometriche.forEach(figuraGeometrica =>{
            console.log("Tipo figura:"+figuraGeometrica.getTipoFigura());
            console.log("Perimetro  :"+figuraGeometrica.getPerimetro());
            console.log("Area       :"+figuraGeometrica.getArea());
        })
    }
}
class Main{
public static main():void{
    var cerchio:IFiguraGeometrica=new Cerchio(10);
    var quadrato:IFiguraGeometrica=new Quadrato(20);
    var rettangolo:IFiguraGeometrica=new Rettangolo(10,20);
    var triangolo:IFiguraGeometrica=new Triangolo(5,10,10);
    var geometria:Geometria=new Geometria();
    geometria.add(cerchio);
    geometria.add(quadrato);
    geometria.add(rettangolo);
    geometria.add(triangolo);
    geometria.stampa();
}    
}    
//Main
Main.main();
-----------------------------------------------------------------------

Tipo figura:Cerchio
Perimetro  :62.83185307179586
Area       :314.1592653589793
Tipo figura:Quadrato
Perimetro  :80
Area       :400
Tipo figura:Rettangolo
Perimetro  :60
Area       :200
Tipo figura:Triangolo
Perimetro  :25
Area       :24.206145913796355
 

 

PROPRIETA' ARCHITETTURALI DEL PARADIGMA OBJECT ORIENTED

Le proprietà Architetturali del paradigma object oriented caratterizzano l'organizzazione strutturale di un'applicazione software
Le proprietà architetturali incidono sulla qualità  delle applicazioni, come ad esempio le prestazioni, la scalabilità, la disponibilità la 
riusabilità e la modificabilità.

COESIONE

Le classi sono Coese se sono disegnate per offrire una soluzione specifica, come ad esempio avviene per i servizi che mettono a disposizione funzioni che  risolvono problemi di un particolare dominio applicativo.

Il pattern MVC (Model View Controller), favorisce il disegno di classi coese,  perché permette di distinguere le classi in base al ruolo che devono avere all'interno dell'applicazione.

Se più classi hanno responsabilità (metodi) e caratteristiche (attributi) comuni, probabilmente bisogna creare una nuova classe che le contiene tutte.

Un bravo programmatore ad oggetti, quando sviluppa un'applicazione, rispetta sempre questa regola:

"Metti il codice dove gli altri si aspettano di trovarlo" .

Le classi di tipo model sono coese, perché tutti i loro metodi interni servono per gestire gli attributi privati, non accessibili ai metodi di altre classi. 

 
class Persona{
    private id:number;
    private nome:string;
    private cognome:string;
    private dataDiNascita:Date;
    private luogoDiNascita:string;
    private sesso:string;
    public setId(id:number):void{
        this.id=id;
    }
    public getId():number{
        return this.id;
    }
    public setNome(nome:string):void{
        this.nome=nome;
    }
    public getNome():string{
        return this.nome;
    }
    public setCognome(cognome:string):void{
        this.cognome=cognome;
    }
    public getCognome(){
        return this.cognome;
    }
    public setDataDiNascita(dataDiNascita:Date):void{
        this.dataDiNascita=dataDiNascita;
    }
    public getDataDiNascita():Date{
        return this.dataDiNascita;
    }
    public setLuogDiNascita(luogoDiNascita:string):void{
        this.luogoDiNascita=luogoDiNascita;
    }
    public getLuogoDiNascita():string{
        return this.luogoDiNascita;
    }
    public setSesso(sesso:string):void{
        this.sesso=sesso;
    }
    public getSesso():string{
        return this.sesso;
    }
    public toString():string{
        let optionsIntl.DateTimeFormatOptions = {
            day: "numeric"month: "numeric"year: "numeric"
        };
 
           return this.id+","+this.nome+","+this.cognome+","+this.dataDiNascita.toLocaleDateString("en-GB"options)+","+this.luogoDiNascita+","+this.sesso;
    }
    public equals(obj:Object):boolean{
        if (this.toString()!=obj.toString()){
            return false;
        }
        return true;
    }
        // Sovraccarico del costruttore
        public constructor();
        public constructor(id:number,nome:string,cognome:string,dataDinascita:Date,luogoDiNascita:string,sesso:string);
        public constructor(id?:number,nome?:string,cognome?:string,dataDinascita?:Date,luogoDiNascita?:string,sesso?:string){
            this.id=id;
            this.nome=nome;
            this.cognome=cognome;
            this.dataDiNascita=dataDinascita;
            this.luogoDiNascita=luogoDiNascita;
            this.sesso=sesso;
        }    
}
 

Un altro esempio di classi coese, sono quelle di tipo CRUD, specializzate per gestire la persistenza delle classi di tipo model.

Una classe CRUD può essere considerata un servizio.

 
 
interface IPersonaCRUD{
    inserisci(persona:Persona):boolean;
    modifica(indice:number,persona:Persona):boolean;
    cancella(indice:number):boolean;
    leggi(indice:number):Persona;
    leggi():Persona[];
}
 
export class PersonaCRUD implements IPersonaCRUD{
    private persone:Persona[];
    inserisci(personaPersona): boolean {
       this.persone.push(persona);
       return true;
    }
    modifica(indice:numberpersonaPersona): boolean {
        this.persone[indice]=persona;
        return true;
    }
    cancella(indicenumber): boolean {
        this.persone.splice(indice,1);
        return true;  
    }
    // Overload (polimorfismo dei metodi)
    leggi(indicenumber): Persona;
    leggi(): Persona[];
    leggi(indice?: number): Persona | Persona[] {
        if (arguments.length==1){
            return this.persone[indice];
        } else{
        return this.persone;
        }
    }
 
}
 

Anche la classe di utilità Math è coesa, perché contiene tutte le funzionalità richieste per gestire operazioni di matematica, di seguito elenchiamo quelle più importanti:

// matematica.ts
class OperazioniMatematiche{
    public static main():void{
        var numeri:number[]=[10,30,20,5,40];
        console.log("Pi greco:"+Math.PI);
        console.log("Arrotonda per eccesso:"+Math.ceil(Math.PI));
        console.log("Arrotonda per difetto:"+Math.round(Math.PI));
        console.log("Valore assoluto di -10:"+Math.abs(-10));
        console.log("Potenza di 5^2:"+Math.pow(5,2));
        console.log("Radice quadrata di 25:"+Math.sqrt(25));
        console.log("Valore massimo di :"+numeri+" -> "+Math.max(10,30,20,5,40));
        console.log("Valore minimo di :"+numeri+" -> "+Math.min(10,30,20,5,40));
        console.log("Valore casuale da 1 a 100:"+Math.ceil(Math.random()*100));
    }
}
OperazioniMatematiche.main();
-----------------------------------------------------------------------------------
Pi greco:3.141592653589793
Arrotonda per eccesso:4
Arrotonda per difetto:3
Valore assoluto di -10:10
Potenza di 5^2:25
Radice quadrata di 25:5
Valore massimo di :10,30,20,5,40 -> 40
Valore minimo di :10,30,20,5,40 -> 5
Valore casuale da 1 a 100:63
 

DISACCOPPIAMENTO

Per Accoppiamento s'intendono i legami (relazioni di dipendenza)  esistenti tra classi diverse della stessa applicazione.
Minore è il livello di accoppiamento tra le classi e maggiore è la manutenibilità del software, perché oltre a favorire la leggibilità del codice, eventuali modifiche ad una classe hanno basse ripercussioni sulle altre classi.

Si crea un accoppiamento forte tra due classi tutte le volte che un metodo di una classe Client, istanzia un oggetto per usare i metodi oppure gli attributi pubblici di una classe Server, come mostra il diagramma seguente:

 L'accoppiamento è debole se il metodo della classe Client riceve come argomento il riferimento della classe Server senza istanziare un oggetto di tipo Server

Esempio 3

Una classe Persona ha un attributo di tipo Indirizzo, composto dal nome della strada, il cap, la città e la provincia.
Per creare l'attributo di tipo Indirizzo nella classe Persona utilizziamo la classe seguente:

 
//indirizzo.ts
export class Indirizzo {
    private nomeStrada:string;
    private cap:string;
    private citta:string
    private provincia:string;
    public getNomeStrada():string{
        return this.nomeStrada;
    }
    public setNome(nomeStrada:string):void{
        this.nomeStrada=nomeStrada;
    }
    public getCap():string{
        return this.cap;
    }
    public setCap(cap:string):void{
        this.cap=cap;
    }
    public getCitta():string{
        return this.citta;
    }
    public setCitta(citta:string):void{
        this.citta=citta;
    }    
    public getProvincia():string{
        return this.provincia;
    }
    public setProvincia(provincia:string):void{
        this.provincia=provincia;
    }    
    public toString():string{
        return this.nomeStrada+","+this.cap+","+this.citta+","+this.provincia;
    }
    public constructor();
    public constructor(nomeStrada:string,cap:string,citta:string,provincia:string);
    public constructor(nomeStrada?:string,cap?:string,citta?:string,provincia?:string){
        this.nomeStrada=nomeStrada;
        this.cap=cap;
        this.citta=citta;
        this.provincia=provincia;    
    }
}
 

 

In questo esempio per creare l'attributo di tipo Indirizzo nella classe Persona, stiamo creando un accoppiamento tra la due classi.

A seconda di come viene impostato il metodo setIndirizzo ed il costruttore della classe Persona, l'accoppiamento diventa alto (forte) oppure basso (debole).

A) Accoppiamento alto

 
//persona_con_indirizzo_accoppiamento_alto.ts
import {Indirizzofrom './indirizzo'
export class Persona{
    private id:number;
    private nome:string;
    private cognome:string;
    private dataDiNascita:Date;
    private luogoDiNascita:string;
    private sesso:string;
    private codiceFiscale:string;
    private indirizzo:Indirizzo=new Indirizzo();
    public setId(id:number):void{
        this.id=id;
    }
    public getId():number{
        return this.id;
    }
    public setNome(nome:string):void{
        this.nome=nome;
    }
    public getNome():string{
        return this.nome;
    }
    public setCognome(cognome:string):void{
        this.cognome=cognome;
    }
    public getCognome(){
        return this.cognome;
    }
    public setDataDiNascita(dataDiNascita:Date):void{
        this.dataDiNascita=dataDiNascita;
    }
    public getDataDiNascita():Date{
        return this.dataDiNascita;
    }
    public setLuogDiNascita(luogoDiNascita:string):void{
        this.luogoDiNascita=luogoDiNascita;
    }
    public getluogoDiNascita():string{
        return this.luogoDiNascita;
    }
    public setSesso(sesso:string):void{
        this.sesso=sesso;
    }
    public getSesso():string{
        return this.sesso;
    }
    public getCodiceFiscale():string{
        return this.codiceFiscale;
    }
    public setCodiceFiscale(codiceFiscale:string):void{
        this.sesso=codiceFiscale;
    }
    public setIndirizzo(nomeStrada:string,cap:string,citta:string,provincia:string){
        this.indirizzo.setNomeStrada(nomeStrada);
        this.indirizzo.setCap(cap);
        this.indirizzo.setCitta(citta);
        this.indirizzo.setProvincia(provincia);
    }
    public getIndirizzo():Indirizzo{
           return this.indirizzo;
    }
    public toString():string{
        let optionsIntl.DateTimeFormatOptions = {
            day: "numeric"month: "numeric"year: "numeric"
        };
 
           return this.id+","+this.nome+","+this.cognome+","+this.dataDiNascita.toLocaleDateString("en-GB"options)+","+this.luogoDiNascita+","+this.sesso+","+this.codiceFiscale+","+this.indirizzo;
    }
    public equals(obj:Object):boolean{
        if (this.toString()!=obj.toString()){
            return false;
        }
        return true;
    }
        // Sovraccarico del costruttore
        public constructor();
        public constructor(id:number,nome:string,cognome:string,dataDinascita:Date,luogoDiNascita:string,sesso:string,codiceFiscale:string,nomeStrada:string,cap:string,citta:string,provincia:string);
        public constructor(id?:number,nome?:string,cognome?:string,dataDinascita?:Date,luogoDiNascita?:string,sesso?:string,codiceFiscale?:string,nomeStrada?:string,cap?:string,citta?:string,provincia?:string){
            if(arguments.length>0){
                this.id=id;
                this.nome=nome;
                this.cognome=cognome;
                this.dataDiNascita=dataDinascita;
                this.luogoDiNascita=luogoDiNascita;
                this.sesso=sesso;
                this.codiceFiscale=codiceFiscale;
                this.indirizzo.setNomeStrada(nomeStrada);
                this.indirizzo.setCap(cap);
                this.indirizzo.setCitta(citta);
                this.indirizzo.setProvincia(provincia);
                    }
        }    
}
 

In questo caso l'accoppiamento tra la classe Persona e la classe Indirizzo è alto, perché se si modificano gli attributi della classe Indirizzo, necessariamente bisogna modificare anche gli argomenti del metodo setIndirizzo ed del costruttore della classe Persona. 

private indirizzo:Indirizzo=new Indirizzo(); 
...
    public setIndirizzo(nomeStrada:string,cap:string,citta:string,provincia:string){
        this.indirizzo.setNomeStrada(nomeStrada);
        this.indirizzo.setCap(cap);
        this.indirizzo.setCitta(citta);
        this.indirizzo.setProvincia(provincia);
    }
...
public constructor(id?:number,nome?:string,cognome?:string,dataDinascita?:Date,luogoDiNascita?:string,sesso?:string,codiceFiscale?:string,nomeStrada?:string,cap?:string,citta?:string,provincia?:string){
            if(arguments.length>0){
                this.id=id;
                this.nome=nome;
                this.cognome=cognome;
                this.dataDiNascita=dataDinascita;
                this.luogoDiNascita=luogoDiNascita;
                this.sesso=sesso;
                this.codiceFiscale=codiceFiscale;
                this.indirizzo.setNomeStrada(nomeStrada);
                this.indirizzo.setCap(cap);
                this.indirizzo.setCitta(citta);
                this.indirizzo.setProvincia(provincia);
                    }
}    

 

B) Accoppiamento basso

 
//persona_con_indirizzo_accoppiamento_basso.ts
import {Indirizzofrom './indirizzo'
export class Persona{
    private id:number;
    private nome:string;
    private cognome:string;
    private dataDiNascita:Date;
    private luogoDiNascita:string;
    private sesso:string;
    private codiceFiscale:string;
    private indirizzo:Indirizzo;
    public setId(id:number):void{
        this.id=id;
    }
    public getId():number{
        return this.id;
    }
    public setNome(nome:string):void{
        this.nome=nome;
    }
    public getNome():string{
        return this.nome;
    }
    public setCognome(cognome:string):void{
        this.cognome=cognome;
    }
    public getCognome(){
        return this.cognome;
    }
    public setDataDiNascita(dataDiNascita:Date):void{
        this.dataDiNascita=dataDiNascita;
    }
    public getDataDiNascita():Date{
        return this.dataDiNascita;
    }
    public setLuogDiNascita(luogoDiNascita:string):void{
        this.luogoDiNascita=luogoDiNascita;
    }
    public getluogoDiNascita():string{
        return this.luogoDiNascita;
    }
    public setSesso(sesso:string):void{
        this.sesso=sesso;
    }
    public getSesso():string{
        return this.sesso;
    }
    public getCodiceFiscale():string{
        return this.codiceFiscale;
    }
    public setCodiceFiscale(codiceFiscale:string):void{
        this.sesso=codiceFiscale;
    }
    public setIndirizzo(indirizzo:Indirizzo){
        this.indirizzo=indirizzo;
    }
    public getIndirizzo():Indirizzo{
           return this.indirizzo;
    }
    public toString():string{
        let optionsIntl.DateTimeFormatOptions = {
            day: "numeric"month: "numeric"year: "numeric"
        };
 
           return this.id+","+this.nome+","+this.cognome+","+this.dataDiNascita.toLocaleDateString("en-GB"options)+","+this.luogoDiNascita+","+this.sesso+","+this.codiceFiscale+","+this.indirizzo;
    }
    public equals(obj:Object):boolean{
        if (this.toString()!=obj.toString()){
            return false;
        }
        return true;
    }
        // Sovraccarico del costruttore
        public constructor();
        public constructor(id:number,nome:string,cognome:string,dataDinascita:Date,luogoDiNascita:string,sesso:string,codiceFiscale:string,indirizzo:Indirizzo);
        public constructor(id?:number,nome?:string,cognome?:string,dataDinascita?:Date,luogoDiNascita?:string,sesso?:string,codiceFiscale?:string,indirizzo?:Indirizzo){
            if(arguments.length>0){
                this.id=id;
                this.nome=nome;
                this.cognome=cognome;
                this.dataDiNascita=dataDinascita;
                this.luogoDiNascita=luogoDiNascita;
                this.sesso=sesso;
                this.codiceFiscale=codiceFiscale;
                this.indirizzo=indirizzo;
            }
        }    
}
 

  

In questo caso l'accoppiamento tra la classe Persona e la classe Indirizzo è basso perché se si modificano gli attributi della classe Indirizzo, non bisogna modificare gli argomenti del metodo setIndirizzo e del costruttore della classe Persona, poiché contengono semplicemente il riferimento della classe indirizzo.

private indirizzo:Indirizzo;
...
    public setIndirizzo(indirizzo;Indirizzo){
        this.indirizzo=indirizzo;
    }
...
public constructor(id?:number,nome?:string,cognome?:string,dataDinascita?:Date,luogoDiNascita?:string,sesso?:string,codiceFiscale?:string,indirizzo?:Indirizzo){
            if(arguments.length>0){
                this.id=id;
                this.nome=nome;
                this.cognome=cognome;
                this.dataDiNascita=dataDinascita;
                this.luogoDiNascita=luogoDiNascita;
                this.sesso=sesso;
                this.codiceFiscale=codiceFiscale;
                this.indirizzo=indirizzo;
                    }
}    

DIPENDECY INJECTION

La Dipendency Injection è una particolare forma del pattern Inversion Of Control (IoC), che rende una classe indipendente dell'inizializzazione delle proprie dipendenze.
Questa caratteristica riduce il livello di accoppiamento tra le classi ed aumenta la manutenibilità dell'applicazione.

In parole semplici, con la Dipendency Injection i metodi oppure i costruttori di una classe non istanziano gli oggetti con il comando new, ma ricevono direttamente i loro riferimento come argomento passato dal contesto applicativo.

Nella programmazione tradizionale è lo sviluppatore che si occupa di tutte le operazioni di creazione, inizializzazione ed invocazione dei metodi degli oggetti, l'IoC invece inverte il control flow facendo in modo che non sia più lo sviluppatore a doversi preoccupare di questi aspetti, ma il framework, che reagendo a qualche “stimolo” se ne occuperà per suo conto.

Se sviluppate con Java il framework più usato è SPRING, se sviluppate con TypeScript il più usato è ANGULAR.

 

Nella prossima lezione vedremo come manipolare gli elementi del DOM delle pagine  HTML.


<< Lezione precedente | Vai alla prima lezione


T U T O R I A L S    S U G G E R I T I


EDUCATIONAL GAMING BOOK (EGB) "H2O"

Nell'era dello SMART LEARNING e di PYTHON i libri non si scrivono, ma si sviluppano, in questo modo chi studia, può sperimentare ed apprendere contemporaneamente; un libro con queste caratteristiche lo possiamo definire un  Educational Gaming Book (EGB).

"H2Oè un EGB che descrive tutte le caratteristiche dell'acqua, la sostanza formata da molecole di H2O, che attraverso il suo ciclo di vita garantisce la sopravvivenza di tutti gli esseri viventi del Pianeta

L'obiettivo dell'EGB è quello di far conoscere ai giovani le proprietà dell'acqua, sotto molti aspetti uniche, per sensibilizzarli a salvaguardare un bene comune raro, indispensabile per la vita


Per il DOWNLOAD di "H2Oclicca qui.

Share Button

TypeScript - Lezione 6: Paradigma Object Oriented (prima parte)

Gino Visciano | Skill Factory - 28/07/2020 23:29:50 | in Tutorials

Il paradigma Object Oriented prevede che le applicazioni siano  composte da un insieme di componenti, chiamti oggetti oppure istanze, che collaborano tra loro per svolgere un lavoro o risolvere un problema.

Il Diagramma di collaborazione seguente mostra un esempio di applicazione Object Oriented.

 

Tutte le applicazioni si possono assemblare utilizzando tre tipi di oggetti: 

- I MODEL sono oggetti che contengono i dati di un entità, corrispondono ai record delle tabelle, permettono di memorizzare temporaneamente i dati in memoria;
- Le 
VIEW sono oggetti oppure viste,  come ad esempio le pagine htmlpermettono la visualizzazione oppure l'inserimento di informazioni;
- I 
CONTROLLER  sono oggetti che hanno il compito di gestire un flusso logico applicativo, all'interno della stessa applicazione ci possono essere anche più CONTROLLER.

L'immagine seguente mostra un diagramma di classe che descrive una classe  che contiene gli attributi di una Persona.

Con una classe di questo tipo è possibile istanziare oggetti di tipo MODEL.

L'immagine seguente mostra il mockup di una pagina.html che permette di inserire i dati che verranno memorizzati in un oggetto di tipo Persona:

L'immagine seguente mostra un diagramma di classe con la classe GestionePersone di tipo CONTROLLER che, attraverso il metodo main, implementa la logica necessaria per gestire oggetti di tipo Persona: 

 

COLLABORAZIONE TRA COMPONENTI

Quando si lavora con un linguaggio ad oggetti bisogna ricordare alcune regole importanti per permettere la collaborazione (comunicazione) tra i componenti dell'applicazione:

1) Una classe diventa un componente (oggetto) quando s'istanzia, solo in questo caso è possibile usare gli attributi ed i metodi pubblici, come mostra il codice TypeScript seguente:

Persona personaUno = new Persona();
Persona personaDue = new Persona();
personaUno.setNome("Pippo");
personaUno.setCognome("Rossi");
personaUno.setEta(35);
personaDue.setNome("Carla");
personaDue.setCognome("Verdi");
personaDue.setEta(30);

L'immagine seguete mostra prima il Diagramma di Classe che descrive la classe Persona, di seguito attraverso un Diagramma ad Oggetti vengono descritti gli stati delle istanze (oggetti) dei due compenenti di tipo MODEL  creati usando la classe Persona.

I due componenti istanziati sono stati allocati in memoria e gli indirizzi (riferimenti) memorizzati nelle variabili personaUno e personaDue di tipo Persona.

2) Gli attributi ed i metodi  pubblici di una classe si definiscono Interfaccia. I componenti possono collaborare (comunicare) tra loro solo attraverso l'interfaccia.  

Ad esempio l'interfaccia della classe Persona è composta solo dai metodi:

public setNome(nome:string):void;
public setCognome(cognome:string):void;
public setEta(eta:number):void;
public getNome():string;
public getCognome():string;
public getEta():int;

perché gli attributi sono tutti privati e non possono essere visibili agli altri componenti.

3) Un componente che usa gli attributi ed i metodi pubblici (interfaccia) di un altro componenete ha il ruolo di Client, l'altro ha il ruolo di Server

L'immagine seguente mostra la classe Prima, di tipo Client, perché attraverso i metodi stampaDivisione() e stampaValore(), utilizza l'attributo valore ed il metodo divisione(...) della classe Seconda, che ha il ruolo di Server.

I metodi di una classe Client per usare gli attributi ed i metodi pubblici (interfaccia) di una classe Server devono istanziarla, come mostra l'esempio seguente:

Esempio 1

 
// prima.ts classe Client
import {Secondafrom './seconda'
export class Prima{
    public stampaDivisione():void{
        //Istanza classe Server
        var seconda:Seconda =new Seconda();
        console.log("Divisione 10/5="+seconda.divisione(10,5));
    }
    public stampaValore():void{
        //Istanza classe Server
        var seconda:Seconda =new Seconda();
        console.log("valore="+seconda.valore);
    }
}
 

 

 
// seconda.ts classe Server
export class Seconda{
    //Interfaccia classe Server perché entrambi gli elementi sono pubblici
    public valore:number=10;
    public divisione(dividendo:number,divisore:number):number{
        return dividendo/divisore;
    }
}
 

 

 
import {Primafrom './prima'
//Istanza classe Prima perché per poter usare 
//i suoi elementi pubblici deve diventare un componente 
var prima:Prima=new Prima();
prima.stampaDivisione();
prima.stampaValore();
 

 

Tra la classe Client Prima e la classe Server Seconda esiste una dipendenza, perché entrambi i metodi stampaDivisione() e stampaValore() di classe Prima istanziano un componente di tipo Seconda.

Quando esiste una dipendenza le classi si dicono accoppiate


PROPRIETA' DEL PARADIGMA OBJECT ORIENTED

Il paradigma Object Oriented prevede tre proprietà di programmazione e due architetturali.

Proprietà di programmazione:

1) Incapsulamento
2) Ereditarietà
3) Polimorfismo

Il Polimorfismo può essere diviso in:

1) Polimorfismo dei metodi: Overload ed Override
2) Polimorfismo degli oggetti, che si può ottenere per ereditarietà oppure per interfaccia.

Le proprietà di programmazione permettono di sviluppare le classi ed impostare le loro caratteristiche ed il loro comportamento

Proprietà architetturali:

1) Coesione
2) Disaccoppiamento

Le proprietà architetturali permettono d'impostare la struttura e l'organizzazione delle applicazioni ad oggetti, per migliorarne le funzionalità e la qualità

 

PROPRIETA' DI PROGRAMMAZIONE DEL PARADIGMA OBJECT ORIENTED

Le proprietà descritte di seguito sono disponibili unicamente nei linguaggio orientatti agli oggetti (Object Oriented),  come ad esempio: C++, C#, Java, TypeScript e Python.

INCAPSULAMENTO

L'incapsulamento, attraverso i modificatori di accesso,  permette di regolare la visibilità e quindi l'utilizzo degli elementi di una classe:

- Attributi
- Metodi
- Costruttori

da parte dei metodi di altre classi.

I modificatori di accesso disponbili in TypeScript sono:

- public         (+, notazione UML)
- private        (-, notazione UML)
- protected  (#, notazione UML)

a)  un elemento è public è visibile a tutti i metodi sia della classe a cui appartiene, sia ai metodi di altre classi.
b)  un elemento è private è visibile solo a tutti i metodi della classe a cui appartiene, ma non è visibile ai metodi di altre classi.
c)  un elemento è protected è visibile solo a tutti i metodi della classe a cui appartiene ed a quelli delle classi che ereditano la classe che contiene l'elemento protected, ma non è visibile ai metodi di altre classi.

 


Esempio 2

 
// incapsulamento.rs
class Test{
public a:number=10;
private b:number=20;
protected c:number=30;
}
class TestA{
public eseguiTest(){
     // Verifica incapsulamento per istanza (dipendenza)
     var test:Test=new Test();
     console.log("a="+test.a+" (public)")
     console.log("b=non visibile (private)");
     console.log("c=non visibile (protected)");
}
}
class TestB extends Test{
    public eseguiTest(){
         // Verifica incapsulamento per ereditarietà
         console.log("a="+this.a+" (public)")
         console.log("b=non visibile (private)");
         console.log("c="+this.c+" (protected)");
    }
    }
 
// Controller
class Main{
    public static main(){
        var testA:TestA=new TestA();
        var testB:TestB=new TestB();
        console.log("----- Test incapsulamento per dipendenza -----")
        testA.eseguiTest();
        console.log("----- Test incapsulamento per ereditarietà -----")
        testB.eseguiTest();
    }
}
 
//main
Main.main();
 
----------------------------------------------------------------------------
----- Test incapsulamento per dipendenza -----
a=10 (public)
b=non visibile (private)
c=non visibile (protected)
----- Test incapsulamento per ereditarietà -----
a=10 (public)
b=non visibile (private)
c=30 (protected)
 

 

EREDITARIETA'

L'Ereditarietà è una tecnica di riuso del codice, questa proprietà permette di creare una nuova classe, ereditando tutti gli elementi public e protected di un'altra classe, chiamata classe padre.
La classe figlia o derivata può contenere nuovi elementi che permettono di specializzare la classe Padre ereditata

L'Ereditarietà è quasi sempre singola, ovvero una classe figlia può ereditare una sola classe per volta, l'unico linguaggio che permette l'ereditarietà multipla è il C++.

 

EREDITARIETA': REGOLA DEL COSTRUTTORE PARAMETRIZZATO

In caso di ereditarietà, se nella classe padre è presente un costruttore parametrizzato, i suoi argomenti devono essere alimentati dal costruttore della classe figlia, con il metodo super(...), come mostra l'immagine seguente:
 

 

POLIMORFISMO DEI METODI

- OVERLOAD

L'Overload è la proprietà dell'Object Oriented che permette di usare nella stessa classe metodi con lo stesso nome, ma firma diversa.

La firma di un metodo è composta dal nome del metodo più i tipi degli argomenti passati, come mostra l'immagine seguente:

Nella stessa classe possono essere presenti più costruttori con lo stesso nome grazie all'overload, come mostra l'esempio seguente:

Persona() // Costruttore dei default
Persona(nome:string,cognome:string,eta:int) // Costruttore parametrizzato

Firma 1=Persona
Firma 2=Persona+string+string+int

Esempio 3

L'esempio seguente mostra la classe Colori con tre metodi con lo stesso nome, ma firma diversa:
1) colora+string, questo metodo fornisce in output il nome del colore fornito in input come argomento;
2) colora+number, questo metodo fornisce in output il colore corrispondente al progressivo numerico fornito in input come argomento;
3) colora+number+number+number, questo metodo fornisce in output il codice esadecimale del colore corrispondente al codice R,G,B (RED=decimale,GREEN=decimale,BLUE=decimale) fornito in input come argomento.
 

Attenzione in TypeScript l'overload si gestisce con una funzione con argomenti opzionali e l'uso d'interfacce che permettono di definire le firme consentite, come mostra il codice seguente:

 
class Colori {
    public colora(valoreUno:string):string;
    public colora(valoreUno:number):string;
    public colora(valoreUno:number,valoreDue:number,valoreTre:number):string;
    public colora(valoreUno:string | number,valoreDue?:number,valoreTre?:number):string{
    if(arguments.length==3){
        return  "#"+valoreUno.toString(16)+valoreDue.toString(16)+valoreTre.toString(16);
    } else{
        if (typeof valoreUno=="number") {
            switch(valoreUno){
                case 1:
                    return "rosso";
                    break;
                case 2:
                    return "verde";
                    break;
                case 3:
                    return "bianco";
                    break;
                default:
                    return "nero";
                    break;
            }
 
        } else{
            return valoreUno;
        }   
    }
  }
// Controller
class Main{
    public static main():void{
var colori:Colori=new Colori();
console.log(colori.colora("rosso"));
console.log(colori.colora(2));
console.log(colori.colora(200,100,255));
    }
}
// main
Main.main();
 
 
--------------------------------------------------
rosso
verde
#c864ff
 

 

- OVERRIDE

L'Override è la seconda proprietà del polimorfismo dei metodi, serve per cambiare il comportamento di un metodo ereditato dalla classe Padre, come mostra l'esempio seguente:

Esempio 4

Se la classe ChiSeiSeconda eredita la classe ChiSeiPrima, il comportamento del metodo toString() è lo stesso, sia per un oggetto di tipo ChiSeiPrima, sia per un oggetto di tipo ChiSeiSeconda.

 
class ChiSeiPrima {
    public toString():string{
           return "Sono la classe ChiSeiPrima!" ;
    }
}
class ChiSeiSeconda extends ChiSeiPrima{
}
// Controller
class Main{
    public static main():void{
        var chiSeiPrima=new ChiSeiPrima();
        var chiSeiSeconda=new ChiSeiSeconda();
        console.log(chiSeiPrima.toString());
        console.log(chiSeiSeconda.toString());
    }
}
// main
Main.main();
 
------------------------------------------
Sono la classe ChiSeiPrima!
Sono la classe ChiSeiPrima!
 

 

Esempio 5

Se sovrascrivete (override) il metodo  toString() nella classe ChiSeiSeconda, allora il comportamento del metodo sarà diveso se l'oggetto è di tipo ChiSeiPrima oppure di tipo ChiSeiSeconda.

 
class ChiSeiPrima {
    public toString():string{
           return "Sono la classe ChiSeiPrima!" ;
    }
}
class ChiSeiSeconda extends ChiSeiPrima{
    //Override
    public toString():string{
        return "Sono la classe ChiSeiSeconda!" ;
 }
}
// Controller
class Main{
    public static main():void{
        var chiSeiPrima=new ChiSeiPrima();
        var chiSeiSeconda=new ChiSeiSeconda();
        console.log(chiSeiPrima.toString());
        console.log(chiSeiSeconda.toString());
    }
}
 
----------------------------------------------
Sono la classe ChiSeiPrima!
Sono la classe ChiSeiSeconda!
 
 

 

- OVERRIDE: OPERATORE SUPER

Quando si sovrascrive (override) un metodo in una classe figlia, per poter utilizzare lo stesso metodo della classe Padre, dovete usare l'operatore super

Ricordate che quando istanziate un oggetto utilizzando una classe, l'operatore this diventerà il riferimento dell'oggetto creato, mentre super diventerà il riferimento dell'oggetto padre. 

 
class ChiSeiPrima {
    public toString():string{
           return "Sono la classe ChiSeiPrima!" ;
    }
}
class ChiSeiSeconda extends ChiSeiPrima{
    //Override
    public toString():string{
        return super.toString()+", Sono la classe ChiSeiSeconda!" ;
 }
}
// main
var chiSeiPrima=new ChiSeiPrima();
var chiSeiSeconda=new ChiSeiSeconda();
console.log(chiSeiPrima.toString());
console.log(chiSeiSeconda.toString());
 
-----------------------------------------------
Sono la classe ChiSeiPrima!
Sono la classe ChiSeiPrima!, Sono la classe ChiSeiSeconda!
 

 

Continua nella prossima lezione dove vedremo il Polimorfismo degli oggetti e le proprietà architetturali del paradigma Object Oriented.


<< Lezione precedente           Lezione successiva >> | Vai alla prima lezione


T U T O R I A L S    S U G G E R I T I


EDUCATIONAL GAMING BOOK (EGB) "H2O"

Nell'era dello SMART LEARNING e di PYTHON i libri non si scrivono, ma si sviluppano, in questo modo chi studia, può sperimentare ed apprendere contemporaneamente; un libro con queste caratteristiche lo possiamo definire un  Educational Gaming Book (EGB).

"H2Oè un EGB che descrive tutte le caratteristiche dell'acqua, la sostanza formata da molecole di H2O, che attraverso il suo ciclo di vita garantisce la sopravvivenza di tutti gli esseri viventi del Pianeta

L'obiettivo dell'EGB è quello di far conoscere ai giovani le proprietà dell'acqua, sotto molti aspetti uniche, per sensibilizzarli a salvaguardare un bene comune raro, indispensabile per la vita


Per il DOWNLOAD di "H2Oclicca qui.

Share Button

TypeScript - Lezione 5: Classi ed Oggetti

Gino Visciano | Skill Factory - 10/07/2020 17:52:46 | in Tutorials

TypeScript pur essendo un linguaggio usato per sviluppare applicazioni lato Front-end, è un linguaggio Object Oriented, quindi è importante conoscere i concetti di Classe ed Oggetto.

Una Classe definisce un tipo di oggetto, in pratica è il codice sorgente dell'oggetto che verrà creato in meomria. L'operazione che trasforma il codice  sorgente della classe in oggetto si chiama istanza

L'esempio seguente mostra come si può istanziare in memoria un oggetto di nome persona usando la classe Persona:

Persona persona=new Persona();

1) Persona  è la classe, rappresenta il tipo di oggetto;
2) persona variabile che contiene l'indirizzo (riferimento)  dell'oggetto istanziato con il comando new;
3) Persona() costruttore, metodo usato per inizializzare l'oggetto creato.  

Istanziare significa creare in memoria con il comando new un oggetto, usando come modello la classe. L'indirzzo dove viene allocato l'oggetto, viene assegnato alla variabile dell'istanza, come ad esempio  persona

In fase di progettazione il linguaggio UML (Unified Modeling Language) è molto utile per disegnare un tipo di classe che poi potra essere scritta con qualunque linguaggio di programmazione object oriented (orientato agli oggetti).

L'esempio seguente mostra il diagramma di classe della classe Persona:

Le Classi  possono contenere i seguenti elementi:

attributi
metodi
costruttori

Per convenzione i nomi delle Classi iniziano sempre con la lettera maiuscola e se sono composti da più parole, anche le altre parole devono iniziare con la lettera maiuscola.

ATTRIBUTI
Gli attributi sono variabili della classe, per questo motivo sono anche chiamate  variabili d'istana, sono le proprietà che si usano per memorizzare i dati che appartengono all'oggetto.

Gli attributi  se sono pubblici (+ simbolo UML) possono anche essere usati dai metodi di altre classi, altrimenti se sono privati (- simbolo UML  possono essere usati solo dai metodi della stessa classe.

Se un attributo è protected (# simbolo UML) , in caso di ereditarietà è visibile anche ai metodi della classe figlia.


METODI
metodi sono funzioni contenute nelle classi, le azioni dei metodi determinano il comportamento degli oggetti.

Nei linguaggi di programmazione ad oggetti, la logica applicativa (istruzioni), può essere implementata solo all'interno dei metodi.

 

 

metodi se sono pubblici   (+ simbolo UML)  possono essere eseguiti anche dai metodi di altre classi, se sono privati  (- simbolo UML) possono essere eseguiti solo dai metodi della stessa classe.

Se un metodo è protected (# simbolo UML) , in caso di ereditarietà è visibile anche ai metodi della classe figlia.

Per convenzione i  metodi che hanno il nome che inizia con i prefissi get e set si usano per assegnare o leggere i valori degli attributi privati dell'oggetto a cui appartengono. 

Ad esempio,  dato che gli  attributi della classe  Persona sono privati, per gestirli dovete usare i seguenti metodi pubblici:

setNome
getNome
setCognome
getCognome
setEta
getEta 

COSTRUTTORI
I costruttori sono metodi speciali usati  per istanziare gli oggetti e per inizializzare gli attributi.

Persona persona=new Persona();

Persona() => costruttore.

Per creare un costruttore inTypeScript  dovete implementare un metodo che si chiama constructor senza indicare il tipo restituito

In una classe deve esistere sempre almeno un costruttore senza argomenti, chiamato costruttore di default, come mostra l'esempio seguente:

public constructor(){}

Se necessario il costruttore di default può anche essere usato per inizializzare gli attributi dell'oggetto creato, come mostra l'esempio seguente:
 
public constructor(){
            this.id=1;
            this.nome="Marco";
            this.cognome="Rossi";
            this.dataDiNascita="05/10/1990";
            this.luogoDiNascita="Milano";
            this.sesso="Maschio";
            this.codiceFiscale="mrcrss90r05l268f";
}

Un costruttore con argomenti si chiama costruttore parametrizzato, a differenza di quello di default, permette di passare i valori per inizializzare l'oggetto durante l'istanza, come mostra l'esempio  seguente:

Persona persona=new Persona(1,'Paolo','Rossi','10/02/1991','Milano','Maschio','pllrss91a02l234f');

L'esempio seguente mostra come si crea un costruttore parametrizzato:

public constructor(id:number,nome:string,cognome:string,dataDinascita:Date,luogoDiNascita:string,sesso:string,codiceFiscale:string){
            this.id=id;
            this.nome=nome;
            this.cognome=cognome;
            this.dataDiNascita=dataDinascita;
            this.luogoDiNascita=luogoDiNascita;
            this.sesso=sesso;
            this.codiceFiscale=codiceFiscale;

Esempio 1

L'esempio seguente mostra come creare una classe Persona con gli attributi privati ed i metodi set e get pubblici.
La parola chiave export indica che la classe può essere importata anche in un altro modulo con il comando import.


export class Persona{
    private id:number;
    private nome:string;
    private cognome:string;
    private dataDiNascita:Date;
    private luogoDiNascita:string;
    private sesso:string;
    private codiceFiscale:string;
    public setId(id:number):void{
        this.id=id;
    }
    public getId():number{
        return this.id;
    }
    public setNome(nome:string):void{
        this.nome=nome;
    }
    public getNome():string{
        return this.nome;
    }
    public setCognome(cognome:string):void{
        this.cognome=cognome;
    }
    public getCognome(){
        return this.cognome;
    }
    public setDataDiNascita(dataDiNascita:Date):void{
        this.dataDiNascita=dataDiNascita;
    }
    public getDataDiNascita():Date{
        return this.dataDiNascita;
    }
    public setLuogDiNascita(luogoDiNascita:string):void{
        this.luogoDiNascita=luogoDiNascita;
    }
    public getluogoDiNascita():string{
        return this.luogoDiNascita;
    }
    public setSesso(sesso:string):void{
        this.sesso=sesso;
    }
    public getSesso():string{
        return this.sesso;
    }
    public getCodiceFiscale():string{
        return this.codiceFiscale;
    }
    public setCodiceFiscale(codiceFiscale:string):void{
        this.sesso=codiceFiscale;
    }
    public toString():string{
        let optionsIntl.DateTimeFormatOptions = {
            day: "numeric"month: "numeric"year: "numeric"
        };
 
           return this.id+","+this.nome+","+this.cognome+","+
                  this.dataDiNascita.toLocaleDateString("en-GB"options)
                  +","+this.luogoDiNascita+","+this.sesso+","+this.codiceFiscale;
    }
    public equals(obj:Object):boolean{
        if (this.toString()!=obj.toString()){
            return false;
        }
        return true;
    }
        // Sovraccarico del costruttore (Overload)
        public constructor();
        public constructor(id:number,nome:string,cognome:string,dataDinascita:Date,
                           luogoDiNascita:string,
                           sesso:string,codiceFiscale:string);
        public constructor(id?:number,nome?:string,cognome?:string,dataDinascita?:Date,
                           luogoDiNascita?:string,sesso?:string,codiceFiscale?:string){
            if(arguments.length>0){
                this.id=id;
                this.nome=nome;
                this.cognome=cognome;
                this.dataDiNascita=dataDinascita;
                this.luogoDiNascita=luogoDiNascita;
                this.sesso=sesso;
                this.codiceFiscale=codiceFiscale;
            }
 
        }    
}
 

 

SOVRACCARICO DEL COSTRUTTORE  IN TYPESCRIPT (OVERLOAD)

L' overload è la proprietà dei linguaggi di programmazione ad oggetti che permettere l'implementazione nella stessa classe di metodi con lo stesso nome, ma firma diversa. 

Si definisce firma il nome di un metodo più i tipi degli argomenti passati in input. 

Ad esempio, le firme dei costruttori della classe Persona, sono le seguenti:

1) constructor
2) constructor, number, string, string,  Date, string, string, string

In TypeScript l'overlad si può applicare usando una funzione con argomenti opzionali che in base al numero di argomenti passati in input assume un comportamento diverso.
Per conoscere quali e quanti argomenti vengono passati ad una funzione con argomenti opzionali potete usare l'interfaccia arguments.
Per definire le firme consentite per eseguire la funzione con argomenti opzionali, dovete indicare le  interfacce corrispondenti, come mostra l'esempio seguente:

// Interfaccia che definisce la firma del costruttore di default
public constructor();
// Interfaccia che definisce la firma del costruttore parametrizzato
public constructor(id:number,nome:string,cognome:string,dataDinascita:Date,luogoDiNascita:string,sesso:string,codiceFiscale:string); 
// Funzione con argomenti opzionali, il punto indicativo "?" rende il parametro facoltativo
public constructor(id?:number,nome?:string,cognome?:string,dataDinascita?:Date,luogoDiNascita?:string,sesso?:string,codiceFiscale?:string){
            if(arguments.length>0){
                this.id=id;
                this.nome=nome;
                this.cognome=cognome;
                this.dataDiNascita=dataDinascita;
                this.luogoDiNascita=luogoDiNascita;
                this.sesso=sesso;
                this.codiceFiscale=codiceFiscale;
            }
}

Esempio 2

L'esempio seguente utilizza la classe Persona, creata nell'esempio precedente, per gestire un array di persone.

L'inserimento dei dati avviene attraverso il Form seguente che permette di aggiungere una persona all'array, con il pulsante "Salva" e visualizzare l'elenco di tutte le persone inserite con il pulsante "Elenco".


 

Per ottenere il Form dovete utilizzare il codice HTML seguente:

 
<!--gui_persona.html-->
<html>
<head>
    <script lang="JavaScript" src="persone.js"></script>
</head>
<body>
<table>
<form>
<tr><th>PERSONA</th><th></th></tr>
<tr><td>Nome:</td><td><input type="text" id="nome" value=""></td></tr>
<tr><td>Cognome:</td><td><input type="text" id="cognome" value=""></td></tr>
<tr><td>Data di nascita:</td><td><input type="text" id="data" value=""></td></tr>
<tr><td>Luogo di nascita:</td><td><input type="text" id="luogo" value=""></td></tr>
<tr><td>Sesso:</td><td><input type="text" id="sesso" value=""></td></tr>
<tr><td>Codice Fiscale:</td><td><input type="text" id="cf" value=""></td></tr>
<tr><td></td><td><input type="button" onclick="salva();" value="Salva"> 
<input type="button" onclick="addElenco();" value="Elenco"> <input type="reset" 
       value="reset"></td></tr>
</form>
</table>
--- Elenco Persone ---
<div id="elenco"></div>
</body>
</html>
 


Il tag <script lang="JavaScript" src="persone.js"></script> permette d'importare il modulo JavaScript, risultato della compilazione con tsc del codice TypeScript seguente:


// persone.ts
import {Personafrom "./persona";
 
var persone:Persona[]=[];  //var persone:Persona[]=[]
var id:number=0;
 
// Funzione associata al metodo onclick del pulsante Salva
function salva():void{
    var nome:string=(<HTMLInputElement>document.getElementById("nome")).value;
    var cognome:string=(<HTMLInputElement>document.getElementById("cognome")).value;
    var strData:string=(<HTMLInputElement>document.getElementById("data")).value;
    var luogo:string=(<HTMLInputElement>document.getElementById("luogo")).value;
    var sesso:string=(<HTMLInputElement>document.getElementById("sesso")).value;
    var cf:string=(<HTMLInputElement>document.getElementById("cf")).value;
    var data:Date=new Date(strData);
    id++;
    persone.push(new Persona(id,nome,cognome,data,luogo,sesso,cf));
 }
 
 
// Funzione associata al metodo onclick del pulsante Elenco
 function addElenco() { 
    // crea un nuovo elemento div
    // gli assegna un contenuto
    var currentDiv = document.getElementById("elenco");  
    persone.forEach((persona:Persona)=>{
     // aggiungi il nodo di testo al div appena creato
    var newDiv = document.createElement("div"); 
     newDiv.style.color="blue";
     newDiv.style.fontSize="20";
     var newContent = document.createTextNode(persona.toString()); 
     newDiv.appendChild(newContent);  
     document.body.insertBefore (newDivcurrentDiv); 
     })
   // aggiungi l'elemento appena creato e il suo contenuto nel DOM
 }
 


L'immagine seguente mostra il Form con l'elenco delle persone inserite: 

INTERFACCE

In TypeScript un'interfaccia può essere usata sia per definire un tipo di dato multivalore che serve ad esempio per creare un oggetto JSON, sia per definire  l'elenco dei metodi astratti da implementare in una classe. In questa lezione ci occuperemo delle interfacce che contengono metodi astratti.

Per comprendere come utilizzare un'interfaccia che contiene metodi astratti, facciamo l'esempio di una classe CRUD che usa come repository array di tipo Persona.
Come è nota la classe per svolgere il proprio compito deve garantire le seguenti operazioni:

1) Inserimento (Create);
2) Lettura (Read), di una o tutte le persone memorizzare nel repository;
3) Modifica (Update);
4) Cancellazione (Delete). 

L'esempio seguente mostra come utilizza un'interfaccia come modello per implementare in una classe che deve svolgere le operazioni previste dal CRUD.

Esempio 3

 
//personacrud.ts
import {Personafrom './persona'
 
interface IPersonaCRUD{
    inserisci(persona:Persona):boolean;
    modifica(indice:number,persona:Persona):boolean;
    cancella(indice:number):boolean;
    leggi(indice:number):Persona;
    leggi():Persona[];
}
 
export class PersonaCRUD implements IPersonaCRUD{
    private persone:Persona[];
    inserisci(personaPersona): boolean {
       this.persone.push(persona);
       return true;
    }
    modifica(indice:numberpersonaPersona): boolean {
        this.persone[indice]=persona;
        return true;
    }
    cancella(indicenumber): boolean {
        this.persone.splice(indice,1);
        return true;  
    }
    // Overload (polimorfismo dei metodi)
    leggi(indicenumber): Persona;
    leggi(): Persona[];
    leggi(indice?: number): Persona | Persona[] {
        if (arguments.length==1){
            return this.persone[indice];
        } else{
        return this.persone;
        }
    }
 
}
 

 

CLASSI ASTRATTE

Nella programmazione ad oggetti una classe astratta è un pattern, perché serve per implementare una soluzione applicativa.
Le classi astratte permettono d'implementare metodi che usano il risultato di uno o più metodi astratti, di cui non ne conosciamo ancora il comportamento.
Naturalmente le classi astratte non possono istanziare oggetti, perché contengono sia metodi implementati, sia metodi astratti e quindi devono necessariamente essere ereditate.
La classe figlia verrà utilizzata per implementare il comportamento dei metodi astratti della classe padre

Esempio 4  

//geometria_astratta.ts
//Classe astratta che può essere solo ereditata
abstract class FiguraGeometrica{
    // Attributo di tipo privato, visibile solo nell'oggetto, globalmente.
    private tipoFigura:string;
    public getInfoFigura():string[]{
        var infoFigura:string[]=[];
        infoFigura.push("Tipo figura:"+this.tipoFigura);
        // Uso il risultato dei metodi astratti
        // che verranno implementati nella classe figlia 
        infoFigura.push(this.getCaratteristiche());
        infoFigura.push("Perimetro  :"+this.getPerimetro());
        infoFigura.push("Area       :"+this.getArea());
        return infoFigura;
    }
    getTipoFigura():string{
        return this.tipoFigura;
    }
    // metodi astratti
    abstract getCaratteristiche():string;
    abstract getPerimetro():number;
    abstract getArea():number;
    // Costruttore alimentato dalla classe figlia
    // viene utilizzato per indicare il tipo di figura geometrica
    public constructor(tipoFigura:string){
        this.tipoFigura=tipoFigura;
    }
}
 
class Cerchio extends FiguraGeometrica{
    // Attraverso il costruttore assegno all'attributo raggio il suo valore
    public constructor(private raggio:number){
        // Il metodo super esegue il costruttore del padre
        // e gli passa il valore "Cerchio"
        super("Cerchio");
    }
    // Implemento i metodi astratti ereditati
    public getCaratteristiche():string{
        return "Raggio     :"+this.raggio;
    }
    public getPerimetro(): number {
        return 2*Math.PI*this.raggio;
    }
    public getArea(): number {
        return Math.pow(this.raggio,2)*Math.PI;
    }
}
 
class Quadrato extends FiguraGeometrica{
    // Attraverso il costruttore assegno all'attributo latoA il suo valore   
    public constructor(private latoA:number){
        // Il metodo super esegue il costruttore del padre
        // e gli passa il valore "Cerchio"
        super("Quadrato");
    }
    // Implemento i metodi astratti ereditati
    public getCaratteristiche():string{
        return "Lato       :"+this.latoA;
    }
    public getPerimetro(): number {
        return 4*this.latoA;
    }
    public getArea(): number {
        return Math.pow(this.latoA,2);
    }
}
 
class Rettangolo extends FiguraGeometrica{
    // Attraverso il costruttore assegno agli attributi 
    // latoA e latoB i loro valori   
    public constructor(private latoA:number,private latoB:number){
        // Il metodo super esegue il costruttore del padre
        // e gli passa il valore "Cerchio"
        super("Rettangolo");
    }
    // Implemento i metodi astratti ereditati
    public getCaratteristiche():string{
        return "Lati       :"+this.latoA+", "+this.latoB;
    }
    public getPerimetro(): number {
        return (2*this.latoA)+(2*this.latoB);
    }
    public getArea(): number {
        return this.latoA*this.latoB;
    }
}
 
class Triangolo extends FiguraGeometrica{
    // Attraverso il costruttore assegno agli attributi 
    // latoA, latoB e latoC i loro valori   
    public constructor(private latoA:number,private latoB:number,private latoC:number){
        // Il metodo super esegue il costruttore del padre
        // e gli passa il valore "Cerchio"
        super("Triangolo");
    }
    // Implemento i metodi astratti ereditati
    public getCaratteristiche():string{
        return "Lati       :"+this.latoA+", "+this.latoB+", "+this.latoC;
    }
    public getPerimetro(): number {
        return this.latoA+this.latoB+this.latoC;
    }
    public getArea(): number {
        let sp=this.getPerimetro()/2;
        let area=Math.sqrt(sp*(sp-this.latoA)*(sp-this.latoB)*(sp-this.latoC))
        return area;
    }
}
class Geometria {
    /* Dichiaro un array di tipo FiguraGeometrica che 
    può contenere cerchi,quadrati, rettangoli e triangoli (Upcasting).  
    Questo è possibile solo perché le classi cerchio,quadrato,
    rettangolo e triangolo sono diventate simili, perché hanno ereditato tutte
    la classe FiguraGeometrica (Polimorfismo degli oggetti)*/
    private figureGeometriche:FiguraGeometrica[]=[]
    // Il metodo add grazie all'Upcasting può ricevere anche 
    // riferimenti di oggetti di tipo cerchio,quadrato, rettangolo e triangolo.
    public add(figuraGeometrica:FiguraGeometrica):void{
        this.figureGeometriche.push(figuraGeometrica);
    }
    public stampa(){
        this.figureGeometriche.forEach(figuraGeometrica =>
            figuraGeometrica.getInfoFigura().forEach(info => console.log(info)))
    }
}
class Main{
public static main():void{
    var cerchio:FiguraGeometrica=new Cerchio(10);
    var quadrato:FiguraGeometrica=new Quadrato(20);
    var rettangolo:FiguraGeometrica=new Rettangolo(10,20);
    var triangolo:FiguraGeometrica=new Triangolo(5,10,10);
    var geometria:Geometria=new Geometria();
    geometria.add(cerchio);
    geometria.add(quadrato);
    geometria.add(rettangolo);
    geometria.add(triangolo);
    geometria.stampa();
}    
}    
//Main
Main.main();
 
-----------------------------------------------------------------------------------
Tipo figura:Cerchio
Raggio     :10
Perimetro  :62.83185307179586
Area       :314.1592653589793
Tipo figura:Quadrato
Lato       :20
Perimetro  :80
Area       :400
Tipo figura:Rettangolo
Lati       :10, 20
Perimetro  :60
Area       :200
Tipo figura:Triangolo
Lati       :5, 10, 10
Perimetro  :25
Area       :24.206145913796355
 

 

CLASSI SINGLETON

Nella programmazione ad oggetti una classe singleton è un pattern, perché serve per implementare una soluzione applicativa.
Le classi singleton permettono d'istanziare una sola ricorrenza di un oggetto per evitare duplicati.
Di solito le classi singleton si usano per creare i repository, array che memorizzano oggetti. 

Esempio 5  

 
//singleton.ts
interface IRepository{
    inserisci(obj:Object):boolean;
    modifica(indice:number,obj:Object):boolean;
    cancella(indice:number):boolean;
    leggi(indice:number):Object;
    leggi():Object[];
}
 
export class Repository implements IRepository{
    // Poiché questa classe non può essere istanziata
    // la variabile che deve contenere il riferimento del singolo
    // oggetto istanziato deve istanziarsi da sola con l'operatore static
    private static instance:Repository=null;
    private repository:Object[]=[];
    // Poiché questa classe non può essere istanziata, il metodo 
    // getRepository() che istanzia l'unica ricorrenza dell'oggetto 
    // di tipo Repository deve istanziarsi da solo con l'operatore static
    public static getRepository():Repository{
        // Se instance è null viene istanziato l'oggetto di tipo Repository
        // altrimento l'oggetto già esiste e viene restituito il suo riferimento 
        if(this.instance==null){
            //Il costruttore può essere eseguito anche se privato
            //perché getRepository() è un metodo della classe
            this.instance=new Repository(); 
        }
        return this.instance;
    }
    inserisci(objObject): boolean {
       this.repository.push(obj);
       return true;
    }
    modifica(indice:numberobjObject): boolean {
        this.repository[indice]=obj;
        return true;
    }
    cancella(indicenumber): boolean {
        this.repository.splice(indice,1);
        return true;  
    }
    // Overload (polimorfismo dei metodi)
    leggi(indicenumber): Object;
    leggi(): Object[];
    leggi(indice?: number): Object | Object[] {
        if (arguments.length==1){
            return this.repository[indice];
        } else{
        return this.repository;
        }
    }
    // Il costruttore di una classe singleton è privato
    // per non permettere d'istanziare oggetti
    private constructor(){}
}
 
// Model utente
class Utente{
    public constructor(private id:number,private nome:string,
                       private cognome:string,eta:number,private sesso:boolean){}
}
 
// Classe Controller
class Main{
    public static main(){
        var utentiUno=Repository.getRepository();
        var utentiDue=Repository.getRepository();
        utentiUno.inserisci(new Utente(1,"Mara","Rossi",30,true));
        utentiUno.inserisci(new Utente(2,"Roberta","Verdi",25,true));
        utentiUno.inserisci(new Utente(3,"Carlo","Bianchi",50,false));
        utentiDue.inserisci(new Utente(4,"Ugo","Rossini",20,false));
        utentiDue.inserisci(new Utente(5,"Raffaele","Palomba",25,false));
        utentiDue.inserisci(new Utente(6,"Corrado","Belvedere",50,false));
        console.log("---------- Prima istanza di Repository ----------");
        utentiUno.leggi().forEach(utente => console.log(utente));
        console.log("---------- Seconda istanza di Repository ----------");
        utentiDue.leggi().forEach(utente => console.log(utente));
    }
}
 
// main
Main.main();
 
------------------------------------------------------------------------------------
---------- Prima istanza di Repository ----------
Utente { id: 1, nome: 'Mara', cognome: 'Rossi', sesso: true }
Utente { id: 2, nome: 'Roberta', cognome: 'Verdi', sesso: true }
Utente { id: 3, nome: 'Carlo', cognome: 'Bianchi', sesso: false }
Utente { id: 4, nome: 'Ugo', cognome: 'Rossini', sesso: false }
Utente { id: 5, nome: 'Raffaele', cognome: 'Palomba', sesso: false }
Utente { id: 6, nome: 'Corrado', cognome: 'Belvedere', sesso: false }
---------- Seconda istanza di Repository ----------
Utente { id: 1, nome: 'Mara', cognome: 'Rossi', sesso: true }
Utente { id: 2, nome: 'Roberta', cognome: 'Verdi', sesso: true }
Utente { id: 3, nome: 'Carlo', cognome: 'Bianchi', sesso: false }
Utente { id: 4, nome: 'Ugo', cognome: 'Rossini', sesso: false }
Utente { id: 5, nome: 'Raffaele', cognome: 'Palomba', sesso: false }
Utente { id: 6, nome: 'Corrado', cognome: 'Belvedere', sesso: false }
 

 

Nella prossima lezione approfondiamo il paradigma Object Oriented.


<< Lezione precedente           Lezione successiva >> | Vai alla prima lezione


T U T O R I A L S    S U G G E R I T I


EDUCATIONAL GAMING BOOK (EGB) "H2O"

Nell'era dello SMART LEARNING e di PYTHON i libri non si scrivono, ma si sviluppano, in questo modo chi studia, può sperimentare ed apprendere contemporaneamente; un libro con queste caratteristiche lo possiamo definire un  Educational Gaming Book (EGB).

"H2Oè un EGB che descrive tutte le caratteristiche dell'acqua, la sostanza formata da molecole di H2O, che attraverso il suo ciclo di vita garantisce la sopravvivenza di tutti gli esseri viventi del Pianeta

L'obiettivo dell'EGB è quello di far conoscere ai giovani le proprietà dell'acqua, sotto molti aspetti uniche, per sensibilizzarli a salvaguardare un bene comune raro, indispensabile per la vita


Per il DOWNLOAD di "H2Oclicca qui.

Share Button
TOP