Usare un oggetto della classe madre come modello?

Salve a tutti,

e` la prima volta che scrivo su questo forum, e in effetti sono
abbastanza nuovo a Ruby (poco più di un mese, ma con esperienze
precedenti di C e Perl).

La domanda in oggetto si esemplifica con questo frammento di codice:

class ClasseSpecializzata < ClasseBase
def initialize(modelloBase)
modelloBase.instance_variables.each do |ivar|
instance_variable_set(
ivar,
modelloBase.instance_variable_get(ivar)
)
end
end

… # altri metodi…

end

oggettoSpecializzato = ClasseSecializzata.new(oggettoBase)

E` un modo per “promuovere” oggettoBase a ClasseSpecializzata.

Il codice è testato e sembra funzionare nella maniera attesa; ma mi
chiedo: esiste un modo più ‘nativo’ e diretto di fare la cosa?

Si`, certo, avrei potuto definire ClasseSpecializzata.initialize in modo
da accettare gli stessi parametri di ClasseBase.initialize e poi usare
super, ma questo comporterebbe almeno due problemi:

  1. devo aver memorizzato da qualche parte i parametri con cui ho
    chiamato a suo tempo ClasseBase.new

  2. lo stato di oggettoBase può essere cambiato dal momento della
    creazione a quello della “promozione”

Grazie a chi vorrà rispondermi!

Guido

mmh… se ho capito bene l’idea che hai sarebbe quella di fare

oggetto_specializzato = ClasseSpecializzata.new(oggetto_base)

giusto ? E’ un pattern un pò strano… mi ricorda il prototyping …

Sandro

2009/7/28 Guido De rosa [email protected]

Il giorno 28 luglio 2009 00.13, Guido De rosa[email protected] ha
scritto:

… # altri metodi…

end

oggettoSpecializzato = ClasseSecializzata.new(oggettoBase)

E` un modo per “promuovere” oggettoBase a ClasseSpecializzata.

Il codice è testato e sembra funzionare nella maniera attesa; ma mi
chiedo: esiste un modo più ‘nativo’ e diretto di fare la cosa?

che io sappia no, farei anch’io così, credo. però vedi però successivo.

Si`, certo, avrei potuto definire ClasseSpecializzata.initialize in modo
da accettare gli stessi parametri di ClasseBase.initialize e poi usare
super, ma questo comporterebbe almeno due problemi:

  1. devo aver memorizzato da qualche parte i parametri con cui ho
    chiamato a suo tempo ClasseBase.new

  2. lo stato di oggettoBase può essere cambiato dal momento della
    creazione a quello della “promozione”

ok, però dipende dall’oggetto, in particolare dalla natura delle
variabili di istanza.

oggettoSpecializzato e oggettoBase condividono le variabili d’istanza,
il che può andare bene oppure no, ad esempio se una variabile è un
file, o un socket, continuare a usare oggettoBase potrebbe
compromettere la consistenza di oggettoSpecializzato o viceversa.

infine potrebbero esserci situazioni particolari in cui lo stato di un
oggetto non risiede interamente nelle sue variabili d’istanza ma
anche, per esempio, nella sua relazione con altri oggetti.

pietro

Guido De Rosa wrote:

class ClasseSpecializzata < ClasseBase
def initialize(modelloBase)
modelloBase.instance_variables.each do |ivar|
instance_variable_set(
ivar,
modelloBase.instance_variable_get(ivar)
)
end
end

… # altri metodi…

end

oggettoSpecializzato = ClasseSecializzata.new(oggettoBase)

E` un modo per “promuovere” oggettoBase a ClasseSpecializzata.

Allora… mi pare di capire che il tuo codice sostanzialmente non
“promuova” l’oggetto, ma lo duplica per cambiargli la classe e
presumibilmente aggiungere dei metodi. Non credo che sia una scelta
ottimale, almeno in ruby.
In alternativa se quello che ti interessa veramente è aggiungere metodi
ad un oggetto già istanziato puoi estendere o aggiungere metodi
direttamente alla classe singleton dell’oggetto stesso.
Tieni poi presente che in ruby conta più la capacità di un oggetto di
rispondere ad un dato metodo piuttosto che la sua appartenenza ad una
classe specifica: il seguente codice funziona correttamente, ma genera
un errore se qualcuno apre la classe Array e patcha #length o Matz si
sveglia male e decide di eliminare il metodo Array#length:

if collection.is_a? Array
puts collection.length
else
puts “I only return arrays length!”
end

Questo invece funzionerà sempre (e come side effect funziona anche su
qualsiasi oggetto per il quale è definito #length):

if collection.respond_to? :length
puts collection.length
else
puts “this object doesn’t have a length method”
end

Pietro G.:

ok, per� dipende dall’oggetto, in particolare dalla natura delle
variabili di istanza.
[…]

Si, e chiaro che dipende molto dalla situazione specifica. Nel mio
caso si tratta di eseguire il comando Linux ip addr show e catturare,
via espressioni regolari, le informazioni sulle interfacce di rete del
sistema. A questo stadio non si fa ancora distinzione fra schede
ethernet o bridge o altro. Solo in una elaborazione successiva si scopre
che pippo0 e` in realtà il bridge fra eth1 e eth2, oppure che wlan0 e
wmaster0 rappresentano in realtà la stessa scheda WiFi…

Appare abbastanza naturale, per esempio, pensare alla classe Bridge come
erede della classe Interface, e che l’oggetto derivato conservi le
variabili di istanza dell’oggetto padre (gli indirizzi IP etc.). Per
design (e per buon senso) nessuno modificherà più l’oggetto base a meno
che non si decida di interrogare nuovamente il sistema operativo per
sapere se lo stato delle interfacce è cambiato.

Sandro P. wrote:

mmh… se ho capito bene l’idea che hai sarebbe quella di fare

oggetto_specializzato = ClasseSpecializzata.new(oggetto_base)

giusto ?

Giusto.

E’ un pattern un po’ strano… mi ricorda il prototyping …

Avevo letto di programmazione prototype-based mi pare proprio su questa
mailing list qualche tempo fa… e in effetti si avvicina un po’ a
quello che avevo in mente…