Lezione del 28/4/2014

File testo

cigarette_smoke.txt

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

File 6.3_self_metodiClasse.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
 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