Oggetti, classi e metodi in Ruby
Quarto appuntamento con il linguaggio di scripting di Sketchup. Parliamo di Oggetti, classi e metodi in Ruby. Lo scopo rimane quello di gettare le basi, arricchire le proprie competenze e quindi utilizzare Ruby per migliorare la produttività nel lavoro con Sketchup.
Se sei approdato su queste pagine, da studente di informatica o come programmatore esperto, perdonami, scoprirai da solo che non è un articolo per te, così come gli altri di questa sezione del blog. Questa serie di articoli è dedicata agli utenti di sketchup che desiderano imparare il linguaggio di scripting di Sketchup.
Appunti di Ruby per Sketchup
Questo il riepilogo degli appunti precedenti:
- Ruby per Sketchup: Numeri e operatori numerici
- Sketchup scripting: le stringhe
- Guida a Ruby per Sketchup: variabili e array
Inoltre, per approfondire ti ricordo la guida... programmazione ad oggetti su html.it
All'inizio della programmazione dei computer, l'unico modo per archiviare i dati era creare variabili, costanti, stringhe e array. Ma col passare del tempo e la complessità delle applicazioni, i programmatori si sono stancati di gestire migliaia di valori disorganizzati.
Così hanno deciso di raggruppare dati e operazioni correlate in strutture chiamate Oggetti. La natura dei dati e delle operazioni in un oggetto sono determinate dalla classe dell'oggetto e le operazioni definite in una classe sono chiamate i suoi metodi.
Interi libri sono stati scritti sull'argomento della programmazione orientata agli oggetti, quindi il trattamento di questo argomento di Ruby sarà vergognosamente breve.
Ci sono “tonnellate” di risorse gratuite sul web che discutono i principi della progettazione orientata agli oggetti.
Oggetti
Per creare un modello su larga scala in SketchUp, devi specificare i valori per molte caratteristiche, tra cui coordinate, materiali, trame e colori. Queste impostazioni sono facilmente accessibili nella finestra di progettazione: fai clic su una linea e SketchUp ti indica la sua lunghezza. Ma nel software, gestire così tanti dati è un compito difficile.
Per rendere agevole la nostra vita, organizziamo le relative caratteristiche in strutture gerarchiche di dati. Ad esempio, se stiamo modellando una casa, creeremo una struttura dati generale per la casa e sottostrutture di livello inferiore per i suoi muri, porte e tetto. Una sottostruttura della porta può contenere sottostrutture che modellano la manopola, la serratura e il rivestimento della porta.
Nel software, queste strutture di dati sono chiamate oggetti. È possibile accedere ad un oggetto proprio come una delle variabili che abbiamo esaminato in precedenza. A differenza di una variabile, un oggetto contiene più valori correlati. Ad esempio, mentre door_height identifica l’altezza di una porta, un oggetto di tipo Porta può contenere valori per altezza, larghezza, profondità, materiale e colore della porta.
È utile distinguere gli oggetti dagli array. In Ruby, un array può contenere elementi di qualsiasi tipo, ma un oggetto contiene solo i dati necessari per modellare una determinata cosa: un oggetto fisico o un principio astratto.
Ad esempio, se il progetto di una casa deve tenere traccia dell'altezza, della larghezza e del materiale di ciascuna porta, questi sono i valori memorizzati da oggetti di tipo Porta. Il disegno può contenere anche oggetti di tipo Finestra, Veranda e Garage.
Due oggetti dello stesso tipo devono avere le stesse caratteristiche, ma non necessariamente gli stessi valori. Se il tipo di porta definisce un'altezza e una larghezza e gli oggetti porta1 e porta2 sono entrambi di tipo Porta, allora porta1 e porta2 devono memorizzare valori per altezza e larghezza, ma non necessariamente gli stessi valori.
Il termine specifico per il tipo di un oggetto è la sua classe. È importante comprendere la relazione tra oggetti e classi, e questo è il fulcro di questo post.
Le Classi
Una classe definisce la struttura di un oggetto nello stesso modo in cui un insieme di progetti definisce la struttura di un edificio o un filamento di DNA definisce la struttura di un organismo. Più specificamente, una classe identifica i dati contenuti in un oggetto e i metodi disponibili per operare sui dati dell'oggetto.
L'argomento della codifica di nuove classi sarà oggetti di post futuri in questa serie di appunti. Per ora, devi solo capire cosa sono le classi e come creare oggetti dalle classi esistenti. Tra le librerie Ruby e l'API SketchUp, ci sono centinaia di classi disponibili.
In Ruby tutto ciò con cui lavoriamo è un oggetto. Pertanto, tutto ciò con cui abbiamo a che fare ha una classe. Il metodo class visualizza il nome della classe di un oggetto, come mostrato nel seguente codice:
5.class, restituisce: Fixnum
3.14159.class, restituisce: Float
"Ciao, mondo".class, restituisce: String
[5, 6, 7] .class, restituisce: Array
Come mostrato, 5 è un oggetto della classe Fixnum (numero intero), 3.14159 è un oggetto della classe Float (numero a virgola mobile), "Hello, world" è un oggetto della classe String e [5, 6, 7 ] è un oggetto della classe Array.
Se analizzi il codice di qualcun altro, il metodo class semplifica la determinazione del tipo di dati con cui hai a che fare.
I due elementi seguenti sono particolarmente importanti e saranno discussi nel prossimo capitolo:
• Edge: un oggetto creato dalla classe Edge rappresenta un segmento di linea in un disegno di SketchUp;
• Face: un oggetto creato dalla classe Face rappresenta una superficie bidimensionale in un disegno di SketchUp.
Ci sono oltre ottanta diverse classi nell’API di SketchUp, puoi visitare il sito web. Lì, puoi cliccare sui collegamenti e vedere come è definita ogni classe.
Metodi di istanza
Gli appunti visti sulle stringhe spiegavano gli operatori di base come + e * e presentava anche un elenco di operazioni denominate metodi. Questi metodi funzionano su oggetti string: se str è una stringa, str.length restituisce il numero di caratteri in str. Allo stesso modo, str.downcase converte i caratteri in minuscolo.
Per un elenco completo dei metodi String, digitare il seguente codice nella Ruby Console:
"Hello".methods
Questo elenca tutti i metodi disponibili per un oggetto String. Se str è una variabile tipo String, è possibile ottenere lo stesso risultato richiamando str.methods. Questi metodi sono definiti nella classe String e tutti gli oggetti String, come str, possono invocarli.
La classe Array fornisce un altro set di metodi per i suoi oggetti, come mostrato qui:
se arr = [0, 1, 2], scrivendo arr.Length la console restituisce: 3
arr.first, restituisce: 0
arr.last, restituisce: 2
Un metodo è una procedura definita in una classe che opera su un dato oggetto. In parole povere, un oggetto rappresenta una "cosa" e un metodo fornisce un "mezzo" per interagire con le caratteristiche della cosa.
I metodi vengono chiamati o richiamati usando la notazione a punti: l’oggetto è seguito da un punto e dal nome del metodo. Ad esempio, se la classe Auto definisce un metodo chiamato reverse e auto1 e auto2 sono oggetti Auto, è possibile chiamare auto1.reverse e auto2.reverse.
Molti metodi richiedono dati aggiuntivi per funzionare. Abbiamo visto il metodo di riempimento nella classe Array (fill); esso necessita di un valore di input per sostituire i valori degli elementi nell’array iniziale.
Questi dati aggiuntivi, chiamati argomenti o parametri, possono essere forniti con o senza parentesi, come mostrato nei seguenti comandi:
dat l’array arr = [0, 1, 2, 3], arr.fill (7) restituisce: [7, 7, 7, 7]
ma anche arr.fill 7 restituisce: [7, 7, 7, 7]
Se un metodo richiede più argomenti, gli argomenti devono essere separati da virgole, indipendentemente dal fatto che l'elenco degli argomenti sia racchiuso tra parentesi.
Se osservi attentamente qualche script in ruby, noterai che molti nomi di metodi terminano con un ? mentre altri finiscono con un =. Questo ti dà un’idea di come funziona il metodo. Se il metodo termina con un ?, restituisce vero o falso. Ad esempio, include? il metodo della classe String restituisce true se l’argomento è parte della String e false in caso contrario.
Vediamo gli esempi:
str = "Hello, world", str.include? "ell", restituisce: vero
str.include? ("word"), restituisce: falso
Se un metodo Ruby termina con =, allora si aggiorna l’oggetto con i dati forniti dal parametro. Ciò può essere dimostrato utilizzando l’operatore [] = della classe Array, che modifica il valore di un elemento dell’array con quello del parametro.
Il seguente comando imposta il terzo elemento di arr uguale a 5:
arr [2] = 5
I metodi Ruby possono essere concatenati insieme. Cioè, se method_B può operare sul valore restituito da method_A, è possibile richiamare entrambi i metodi con method_A.method_B.
Ad esempio, supponiamo che tu voglia invertire i caratteri nella conversione maiuscola di "Hello". Puoi farlo usando più comandi, come mostrato di seguito:
str = " Hello ", str1 = str.upcase, restituisce: HELLO
str2 = str1.reverse, restituisce: OLLEH
Oppure puoi ottenere lo stesso risultato in un solo comando:
str = "Hello".upcase.reverse, restituisce: OLLEH
In questo esempio, il metodo inverso opera sul risultato di "Hello".upcase. Il concatenamento dei metodi riduce la quantità di codice che è necessario immettere, ma rende il codice leggermente meno leggibile.
Metodi di classe
Nel paragrafo precedente implica che tutti i metodi definiti in una classe sono accessibili solo tramite oggetti. Non è sempre vero. Alcuni metodi in una classe operano sulla classe stessa. I metodi che operano su classi sono chiamati metodi di classe. I metodi che operano su oggetti sono chiamati metodi di istanza perché un oggetto è un'istanza di una classe.
C'è un metodo di classe importante contenuto in ogni classe Ruby. Questo è il metodo “New” che crea un nuovo oggetto da una classe.
Ad esempio, il comando seguente chiama il metodo New della classe String per creare un nuovo oggetto String:
new_str = String.new
quindi se digito new_str.class, la console restituisce String
La stragrande maggioranza dei metodi che useremo sono metodi di istanza. Si può presumere che qualsiasi metodo discusso qui, sia un metodo di istanza a meno che non sia specificamente descritto come un metodo di classe.
Ereditarietà delle classi
In molte situazioni, potrebbe essere necessario accedere a classi con caratteristiche in comune. Per esempio, se sei un architetto, potresti dover modellare hotel e ospedali. Le due strutture sono diverse e richiedono classi distinte: hotel e ospedale.
Ma le due classi contengono anche caratteristiche simili, come posizione, materiale e numero di piani. Per questo motivo, i seguenti metodi potrebbero applicarsi ugualmente bene alle classi hotel o ospedale:
- num_stories: il numero di storie nella struttura
- location: la posizione geografica della struttura
- materiale: il tipo di materiale utilizzato per costruire la struttura
Piuttosto che codificare due volte gli stessi metodi, è più efficiente inserirli in una terza classe in modo che siano disponibili per gli oggetti di hotel e ospedale. Questa terza classe dovrebbe incarnare l’unione delle due classi e in questo esempio chiameremo la classe comune Edificio.
Stabiliremo inoltre una relazione tra Edificio, Hotel e Ospedale in modo tale che Hotel e Ospedale ricevano entrambi i metodi definiti in Edificio.
Questa relazione tra le classi si chiama ereditarietà. Si dice che sia hotel che ospedale ereditino da edificio. In questo esempio, edificio viene chiamato superclasse di hotel e ospedale, mentre hotel e ospedale vengono chiamati sottoclassi di edificio.
La Figura 2.4 mostra l’aspetto di una gerarchia ereditaria di classe.
Ora puoi definire num_stories, ubicazione e metodi materiali nella singola classe Building e, se devi riscriverne uno, devi solo modificare una singola classe. Inoltre, creando la classe Building, puoi aggiungere facilmente altre classi che rappresentano edifici come biblioteche, chiese e negozi.
Diamo un’occhiata a un esempio reale dell'eredità di classe. L'interprete Ruby elabora i numeri in modo diverso a seconda della quantità di memoria che occupano. Se un numero intero occupa 31 bit o meno, è un oggetto Fixnum. Se un numero intero occupa più di 31 bit, è un oggetto Bignum. Questo è il motivo per cui 24.class restituisce Fixnum e 1234567890.class restituisce Bignum.
Le due classi richiedono metodi diversi per determinate operazioni, ma tra le due, molti dei metodi possono rimanere gli stessi. Ad esempio, il metodo successivo restituisce il numero intero successivo in ordine numerico. 24.next restituisce 25 e 1234567890.next restituisce 1234567891.
Per questo motivo, Ruby ha una classe specifica per numeri interi chiamati Integer. Metodi comuni come next sono inseriti nella classe Integer e poiché Fixnum e Bignum ereditano entrambi da Integer, il metodo è disponibile per gli oggetti di entrambe le classi. La Figura 2.5 mostra come Integer, Fixnum e Bignum sono posizionati nella gerarchia di classi numeriche di Ruby.
Vedremo più avanti come creare classi e sottoclassi nel codice Ruby. Per ora, tutto ciò che devi capire sull'ereditarietà delle classi è questo: se la Classe B eredita dalla Classe A (ovvero la Classe A è la super classe della Classe B), allora tutti i metodi in A sono disponibili per la Classe B. Ciò significa che qualsiasi oggetto della classe B può accedere agli stessi metodi di un oggetto della classe A.
Conclusione della prima parte
Con questo post si conclude la sezione del libro di Mattew Scarpino dedicata alla struttura dei dati. Dalla prossima serie di appunti inizierai ad entrare nel cuore dello scripting studiando le strutture principali e il modello ad oggetti d Sketchup.
Scrivi nei commenti se hai idee o materiale da condividere. Dimmi se questa serie di appunti ti è utile, dammi una mano a renderle migliori.
Ti ricordo le ottime guide in italiano su Ruby:
- html.it - Guida a Ruby
- mrwebmaster.it - Guida a Ruby
Alla prossima!
Comments