Lezione del 28/4/2014¶
File testo
Introduzione alle classi
File 6.1_intro_classi.rb
1#!/usr/bin/env ruby
2#-------------------------------------------------------------------------#
3# Esercitazioni in Laboratorio per il Corso di #
4# Fondamenti di Informatica e Calcolo Numerico, AA 2013/2014 #
5# #
6# Autori: Enrico Bertolazzi e Carlos Maximiliano Giorgio Bort #
7# Dipartimento di Ingeneria Industriale, Universita` di Trento #
8# Sito web: http://www.ing.unitn.it/~bertolaz/ #
9# #
10# Contatti: enrico.bertolazzi@unitn.it, cm.giorgiobort@unitn.it #
11# #
12# Copyright (c) 2014 E.Bertolazzi e C.M. Giorgio Bort #
13#-------------------------------------------------------------------------#
14
15=begin
16In questa lezione vediamo una introduzione alla programmazione ad oggetti,
17punto di forza dei moderni linguaggi di programmazione, come C++, Python,
18Java, e Ruby.
19UN OGGETTO E' UNA ISTANZA DI UNA CLASSE.
20Vediamo quindi brevemente cos'e' una classe, e cosa vuol dire istanziare una
21classe per creare un oggetto.
22=end
23
24=begin
25CLASSI:
26 una classe e' un tipo di dato, definito da:
27 - attributi: variabili/costanti che definiscono le proprieta' degli oggetti
28 - metodi: funzioni interne, che posso essere applicate agli attributi, ma
29 anche a variabili esterne alla classe
30 Nelle lezioni successive vedremo che classi diverse possono essere messe in
31 relazione attraverso la relazione di EREDITARIETA'. Ereditare una classe
32 significa creare nuove classi partendo da classi pre-esistenti ed
33 estendendole con caratteristiche aggiuntive.
34
35 N.B.: IN RUBY quasi TUTTO E' UN OGGETTO. Ogni valore booleano, intero, float,
36 stringa, array, hash, struct, e classe sono FIGLI (i.e. ereditano) da altre
37 classi, che a loro volta ereditano dalla classe 'Class'. Posso verificare
38 cio' invocando il metodo 'class':
39=end
40s = 'ciao'
41puts "s e' una classe #{s.class}"
42puts "#{s.class} e' una classe #{s.class.class}"
43puts "\n"*3
44
45=begin
46OGGETTI:
47 abbiamo detto che un oggetto e' una istanza di una classe. Istanziare
48 significa allocare della memoria per l'oggetto, e inizializzare la classe.
49 Per inizializzare una classe e' necessario invocare il suo metodo
50 costruttore, che in Ruby si chiama 'new'. Ad esempio, data una classe
51 'Cane', creero' l'oggetto 'fido' con il seguente comando:
52 fido = Cane.new
53=end
54
55=begin
56ESEMPIO:
57 definiamo una classe e creiamo un oggetto istanziandola. Suppongo di
58 voler creare un Juke Box con le informazioni delle mie canzoni preferite.
59 Ogni canzone sara' una classe
60
61Nota: ' buona norma dare i nomi alle classi con la prima lettera maiuscola.
62 Se il nome della mia classe e' composto da piu' parole adottero' la 'CamelCase'
63 notation (e.g. 'ClasseDiProva')
64=end
65class Canzone
66 # 1) 'initialize' e' in nome del metodo COSTRUTTORE, che verra' invocato quando
67 # istanzio la classe. In questo caso il costruttore ha tre argomenti:
68 # nome (Stringa) della canzone
69 # artista (Stringa) nome del cantante
70 # durata (Float) durata –in secondi– del brano
71 def initialize(nome, artista, durata)
72 # Le variabili che iniziano con la chiocciolina @ e sono definite dentro
73 # alla classe sono chiamate VARIABILI DI ISTANZA. Queste rappresentano gli
74 # ATTRIBUTI della mia classe, e sono definite (i.e. hanno un valore diverso
75 # da 'nil') solo allorquando la classe sia stata istanziata.
76 # Lo SCOPE degli attributi e' tutto a classe.
77 ### Per inizializzare la mia classe canzone faro':
78 ### c1 = Song.new('Arabella', 'Arctic Monkeys', 207)
79 @nome = nome
80 @artista = artista
81 @durata = durata
82 end
83end
84
85# Per inizializzare la mia classe canzone faro':
86c1 = Canzone.new('Arabella', 'Arctic Monkeys', 207)
87puts c1.inspect
88
89
90
91
92class Canzone
93 # 2) Al momento la mia classe ha un costruttore che gli ho definito io, ma
94 # anche tutte le funzioni della classe da cui eredita. Abbiamo detto che
95 # in Ruby ogni classe eredita dalla classe 'Class', infatti:
96 # c1.class.class -> Class
97 # Ho quindi ereditato tutti i metodi di 'Class', che elenco con:
98 # puts Class.methods.sort
99 #
100 # Ad esempio vedo che ho il metodo 'inspect', che mi da una descrizione
101 # della mia istanza. Tuttavia l'output del metodo non e' molto leggibile,
102 # quindi posso sovrascrivere questo metodo.
103 def inspect
104 # Nota: per interpolare variabili di istanza in una stringa posso scrivere:
105 # "#{@nome}" oppure "#@nome"
106 return "Canzone: #@nome -- #@artista : #@durata"
107 end
108end
109puts "> Nuovo inspect:"
110puts c1.inspect
111
112
113# 3) Accessori: come posso fare a leggere il nome della mia canzone? Potrei
114# pensare di scrivere:
115# puts c1.nome
116# ma Ruby mi dira' che in metodo 'nome' non e' stato definito per la mia classe
117# c1. Devo quindi definire dei metodi che mi permettano di leggere, ed in caso
118# scrivere, gli attributi (i.e. le variabili di istanza) del mio oggetto.
119# Questo lo posso fare con due metodi:
120class Canzone
121
122 # 3.1) definisco esplicitamente i metodi accessori...
123 # per leggere il nome:
124 # def nome
125 # return @nome
126 # end
127 # per scrivere il nome:
128 # def nome=(nuovo_nome)
129 # @nome = nuovo_nome
130 # end
131
132 # 3.2) oppure posso creare degli accessori attraverso delle scorciatoie:
133 # attr_reader :nome
134 # attr_writer :nome
135 # quando sono interessato sia all'accessore per la lettura che
136 # a quello per la scrittura posso scrivere direttamente:
137 attr_accessor :nome, :artista, :durata
138end
139
140puts c1.nome
141c1.nome = "R U mine?"
142puts c1.nome
143
144
145
146leggi pixel, accendi e spegni pixel
File 6.2_ereditarieta.rb
1#!/usr/bin/env ruby
2#-------------------------------------------------------------------------#
3# Esercitazioni in Laboratorio per il Corso di #
4# Fondamenti di Informatica e Calcolo Numerico, AA 2013/2014 #
5# #
6# Autori: Enrico Bertolazzi e Carlos Maximiliano Giorgio Bort #
7# Dipartimento di Ingeneria Industriale, Universita` di Trento #
8# Sito web: http://www.ing.unitn.it/~bertolaz/ #
9# #
10# Contatti: enrico.bertolazzi@unitn.it, cm.giorgiobort@unitn.it #
11# #
12# Copyright (c) 2014 E.Bertolazzi e C.M. Giorgio Bort #
13#-------------------------------------------------------------------------#
14
15=begin
16Nell'esempio precedente abbiamo visto cos'e' una classe, un oggetto, ed abbiamo
17parlato brevemente di cos'e' l'ereditarieta'. In questo esempio tratteremo
18l'ereditarieta' in modo piu' completo
19=end
20
21# Definisco la classe Canzone con il metodo costruttore, inspect, e gli
22# accessori
23class Canzone
24 # accessori
25 attr_accessor :nome, :artista, :durata
26
27 # Costruttore
28 def initialize(nome, artista, durata)
29 @nome = nome
30 @artista = artista
31 @durata = durata
32 end
33
34 def inspect
35 return "Canzone: #@nome -- #@artista : #@durata"
36 end
37end
38
39# L'ereditarieta' mi permette di creare una classe che e' una specializzazione di
40# un'altra classe. Ad esempio, creo una classe 'CanzoneKaraoke' e' deve essere
41# come la classe 'Canzone', con l'unica differenza che deve avere anche
42# informazioni sul testo della canzone.
43# Devo quindi modificare soltanto il costruttore della classe
44class CanzoneKaraoke < Canzone
45 attr_reader :testo
46
47 def initialize(nome, artista, durata, testo)
48 # il metodo 'super' messo qui richiama il costruttore di 'Canzone'
49 super(nome, artista, durata)
50 @testo = testo
51 end
52end
53
54# Proviamo ora la nostra classe 'CanzoneKaraoke'
55# carico il testo della canzone da un file
56testo = ""
57IO.foreach('testi/cigarette_smoke.txt'){|line| testo << line}
58
59k1 = CanzoneKaraoke.new('cigarette smoke', 'Arctic Monkeys', 176, testo)
60# visualizziamo le informazioni sulla canzone:
61puts k1.inspect
62# mi restituisce: > Canzone: cigarette smoke -- Arctic Monkeys : 176
63# che e' proprio l'output che avevo definito nella classe 'Canzone', ovviemente
64# senza informazioni sul testo. Modifico quindi il metodo 'inspect' di
65# 'CanzoneKaraoke'
66class CanzoneKaraoke < Canzone
67 def inspect
68 # 'super' in questo caso dice a Ruby di invocare il metodo 'initialize' di
69 # 'Canzone'
70 descrizione = super
71 return descrizione + " [ #{@testo[0..20]} ... ]"
72 end
73end
74puts k1.inspect
1#!/usr/bin/env ruby
2#-------------------------------------------------------------------------#
3# Esercitazioni in Laboratorio per il Corso di #
4# Fondamenti di Informatica e Calcolo Numerico, AA 2013/2014 #
5# #
6# Autori: Enrico Bertolazzi e Carlos Maximiliano Giorgio Bort #
7# Dipartimento di Ingeneria Industriale, Universita` di Trento #
8# Sito web: http://www.ing.unitn.it/~bertolaz/ #
9# #
10# Contatti: enrico.bertolazzi@unitn.it, cm.giorgiobort@unitn.it #
11# #
12# Copyright (c) 2014 E.Bertolazzi e C.M. Giorgio Bort #
13#-------------------------------------------------------------------------#
14
15=begin
16 Vedremo ora cos'e' in ruby la parola chiave 'self'. Quando usata all'interno
17 di una classe, la parola 'self' e' utilizzata per riferirsi all'oggetto (i.e.
18 istanza) corrente.
19
20 Vedremo inolte cosa sono i metodi e le variabili di classe
21=end
22
23
24class Item1
25
26 # metodo di istanza. E' creato solo dopo che ho instanziato la classe
27 def initialize(item_nome)
28 @item_nome = item_nome
29 end
30
31 # metodo di istanza
32 def show
33 # 'self' mi restituisce la rappresentazione dell'istanza dell'oggetto
34 puts "Metodo di istanza 'show' invocato per #{self}"
35 end
36
37 # se voglio una rappresentazione piu' leggibile
38 #def to_s
39 # "Item: #{@item_nome}"
40 #end
41
42end
43
44t = Item1.new('test')
45t.show
46
47
48############################################
49#### METODI DI CLASSE ######################
50############################################
51puts "_"*40
52class Item2
53 # aggiungendo un 'self' al nome del metodo creo un metodo di classe. Questo
54 # metodo esiste anche senza instanziare la classe
55 def self.show_class
56 puts "Invocato metodo di classe"
57 end
58
59 def show_instance
60 puts "Metodo di istanza"
61 #puts "La variabile di instanza vale #{@var_instance}"
62 end
63end
64Item2.show_class # ora uso il metodo 'show' senza istanziare la classe
65#Item2.show_var_instance # da errore perche' la classe non e' stata inizializzata
66
67# in alternativa avrei potuto scrivere
68=begin
69class Item2
70 class << self
71 def show
72 puts "Invocato metodo di classe"
73 end
74 end
75end
76=end
77
78
79#====#====#====#====#====#====#====#====#====#====#====#====#====#====#====#
80#N.B. I metodi di classe non hanno accesso ai metodi di istanza, o alle
81# variabili di istanza. Al contrario, metodi di istanza possono accedere
82# alle variabili ed ai metodi di classe. Verifichiamo la prima affermazione:
83#====#====#====#====#====#====#====#====#====#====#====#====#====#====#====#
84puts "_"*40
85class Item3
86 # aggiungendo un 'self' al nome del metodo creo un metodo di classe. Questo
87 # metodo esiste anche senza instanziare la classe
88 def self.show_class
89 #show_instance # questo da errore
90 puts "@var_instanza = #{@var_instanza}" # questo da 'nil'
91 puts "Invocato metodo di classe"
92 end
93
94 def show_instance
95 @var_instanza = 3
96 puts "Metodo di istanza"
97 #puts "La variabile di instanza vale #{@var_instance}"
98 end
99end
100Item3.show_class
101
102
103
104############################################
105#### VARIABILI DI CLASSE ###################
106############################################
107puts "_"*40
108class Pianeta
109 # le variabili di classe si definiscono con due '@'
110 @@numero_pianeti = 0
111
112 def initialize(name)
113 @name = name
114 @@numero_pianeti += 1
115 end
116
117 # definisco un metodo di classe che mi permette di accedere
118 # alla variabile di istanza numero_pianeti
119 def self.numero_pianeti
120 @@numero_pianeti
121 end
122end
123
124Pianeta.new("earth")
125Pianeta.new("uranus")
126puts "Il mio sistema planetario ha #{Pianeta.numero_pianeti} pianeti"
127# le variabili di classe possono essere usate per salvare dati che appartengono
128# a una classe, ma non ad una istanza.
129
130
131
132
133
134############################################
135#### VARIABILI DI ISTANZA DI CLASSE ########
136############################################
137class Foo
138 # N.B: una variabile nominata con un solo '@' e definita nel corpo della
139 # classe si chiama VARIABILE DI ISTANZA DI CLASSE
140 @contatore_inst_class = 0
141
142 @@contatore_class = 20
143
144 def aumenta_cont_inst_class # questo metodo dara' errore!
145 @contatore_inst_class += 1
146 end
147
148 def aumenta_cont_class
149 # questo metodo FUNZIONA perche' POSSO USARE VARIABILI (ma anche metodi)
150 # DI CLASSE NEI METODI di istanza
151 @@contatore_class += 1
152 end
153
154 def self.increment_counter
155 @contatore_inst_class += 1
156 end
157
158 def self.current_count_inst_class
159 @contatore_inst_class
160 end
161
162 def self.curret_count_cl
163 @@contatore_class
164 end
165end
166
167puts Foo.increment_counter # OK, funziona
168
169f = Foo.new
170#puts f.aumenta_cont_inst_class
171puts "f.aumenta_cont_class #{f.aumenta_cont_class}"
172# questo da errore perche' NON POSSO USARE VARIABILI DI
173# ISTANZA DI CLASSE NEI METODI DI ISTANZA
174
175
176
177# e che differenza c'e' tra '@@contatore_class' e '@contatore_inst_class'? Vediamolo...
178class Bar < Foo
179 @contatore_inst_class = 100 # se non la definisco, vale 'nil', il suo valore non e' ereditato
180 @@foo_var_cl = 140 # questo NON VIENE SOVRASCRITTO!!!
181end
182puts "Variabile @contatore_inst_class in Foo #{Foo.current_count_inst_class}"
183puts "Variabile @contatore_inst_class in Bar #{Bar.current_count_inst_class}"
184
185puts "Variabile @@contatore_class in Foo #{Foo.curret_count_cl}"
186puts "Variabile @@contatore_class in Bar #{Bar.curret_count_cl}"
187
188=begin RIASSUMENDO
189
190A) I metodi di classe non hanno accesso ai metodi di istanza,
191 o alle variabili di istanza. Al contrario, metodi di istanza
192 possono accedere alle variabili ed ai metodi di classe.
193
194B) Le variabili di istanza sono disponibili solo per istanze di classi,
195 e si scrivono come '@foo'. Le variabili di classe invece sono disponibili
196 sia per i metodi di classe che per i metodi di istanza, e si scrivono
197 come '@@foo'.
198
199C) Le variabili di istanza di classe si scrivono come le variabili di istanza
200 ('@foo') ma vanno dichiarate nel corpo della classe e hanno proprieta' molto
201 diverse dalle variabili di istanza.
202
203D) Le differenze tra VARIABILI DI CLASSE e VARIABILI DI ISTANZA DI CLASSE sono:
204
205 1) le variabili di istanza di classe NON PERMETTONO LA CONDIVISIONE DI DATI
206 ATTRAVERSO TUTTA LA CATENA DI EREDITARIETA`
207 (cosa che invece fanno le variabili di classe).
208
209 2) le variabili di istanza di classe possono essere
210 USATE SOLO IN METODI DI CLASSE
211=end