Forum: Italian Ruby user group aiuto programmazione OO

Posted by Alessandro Barracco (bomastudio)
on 2010-01-15 10:59
Salve sono nuovo del forum e un programmatore 'newbie' (si dice cosi?).
Sto tentando di scrivere un preprocessore grafico per un soft di calcolo
(tipo CAD). Ho necessità di gestire alcuni elementi del tipo

Nodi
Aste
Piastre

Ho creato le corrispondenti classi.

La classe nodo accetta come parametri
id - il numero univoco
x - coordinata x
y - coordinata y
z - coordinata z
vincolo - codice numerico

La classe asta accetta come parametri:
id - il numero univoco
ni - nodo iniziale
nf - nodo finale
tipo - codice alfanumerico
sezione - intero
materiale - intero

Ad esempio l'asta n. 15 ha come estremi il nodo 1 e il nodo 20.

Secondo voi la classe Asta deve ereditare da Nodo oppure è inutile?
Posted by Simone Federici (Guest)
on 2010-01-15 11:19
(Received via mailing list)
Non conosco il dominio del problema, ma da quello che dici tu non vedo
relazione tra un nodo e un asta.

A naso, se un asta è composta da due nodi, asta e nodo sono oggetti del
dominio distinti.
Non essendoci relazione di "parentela" nel mondo reale, non userei
l'ereditarietà.

Simone Federici
-----------------------------------
Architect



2010/1/15 Alessandro Barracco <bomastudio@gmail.com>
Posted by Pietro Giorgianni (giorgian)
on 2010-01-15 11:24
(Received via mailing list)
Il 15 gennaio 2010 10.59, Alessandro Barracco <bomastudio@gmail.com> ha 
scritto:
> Salve sono nuovo del forum e un programmatore 'newbie' (si dice cosi?).
ciao e benvenuto!
> Secondo voi la classe Asta deve ereditare da Nodo oppure è inutile?
in genere, quello che più conta non sono i dati, ma il comportamento;
che accettino parametri simili non è importante, la domanda è cosa
fanno esattamente queste classi; se vedi che hanno molti metodi in
comune, puoi optare per l'ereditarietà - ma magari, se l'asta non è un
caso particolare di nodo (e mi sembra di capire che non lo è), la cosa
più giusta è che entrambi ereditino da un capostipite comune.


pietro
Posted by Alessandro Barracco (bomastudio)
on 2010-01-15 11:27
Simone Federici wrote:
> Non conosco il dominio del problema, ma da quello che dici tu non vedo
> relazione tra un nodo e un asta.
> 
> A naso, se un asta � composta da due nodi, asta e nodo sono oggetti del
> dominio distinti.
> Non essendoci relazione di "parentela" nel mondo reale, non userei
> l'ereditariet�.


OK grazie.
Posted by Alessandro Barracco (bomastudio)
on 2010-01-15 11:28
Pietro Giorgianni wrote:
> Il 15 gennaio 2010 10.59, Alessandro Barracco <bomastudio@gmail.com> ha 
> scritto:
>> Salve sono nuovo del forum e un programmatore 'newbie' (si dice cosi?).
> ciao e benvenuto!
>> Secondo voi la classe Asta deve ereditare da Nodo oppure � inutile?
> in genere, quello che pi� conta non sono i dati, ma il comportamento;
> che accettino parametri simili non � importante, la domanda � cosa
> fanno esattamente queste classi; se vedi che hanno molti metodi in
> comune, puoi optare per l'ereditariet� - ma magari, se l'asta non � un
> caso particolare di nodo (e mi sembra di capire che non lo �), la cosa
> pi� giusta � che entrambi ereditino da un capostipite comune.
> 
> 
> pietro

Chiarissimo. grazie
Posted by Alessandro Barracco (bomastudio)
on 2010-02-06 15:55
Pietro Giorgianni wrote:
> Il 15 gennaio 2010 10.59, Alessandro Barracco <bomastudio@gmail.com> ha 
> scritto:
>> Salve sono nuovo del forum e un programmatore 'newbie' (si dice cosi?).
> ciao e benvenuto!
>> Secondo voi la classe Asta deve ereditare da Nodo oppure � inutile?
> in genere, quello che pi� conta non sono i dati, ma il comportamento;
> che accettino parametri simili non � importante, la domanda � cosa
> fanno esattamente queste classi; se vedi che hanno molti metodi in
> comune, puoi optare per l'ereditariet� - ma magari, se l'asta non � un
> caso particolare di nodo (e mi sembra di capire che non lo �), la cosa
> pi� giusta � che entrambi ereditino da un capostipite comune.
> 
> 
> pietro

Ancora dubbi.......

Ho creato due classi:

# La classe Nodo crea un oggetto nodo.
# Ogni istanza della classe e' identificata da un numero univoco (id)
# La classe necessita di 5 parametri + 1 opzionale: id, x, y, z, 
vincolo, [costante elastica]
class Nodo
  # Numero identificativo del nodo
  attr_accessor :id
  # Coordinata x
  attr_accessor :x
  # Coordinata y
  attr_accessor :y
  # Coordinata z
  attr_accessor :z
  # Codice di vincolo. E' costituito da tre strighe
  # che si riferiscono alle tre componenti di movimento del nodo
  # (nell'ordine: traslazione lungo x, lungo y e rotazione attorno z).
  # 0 = movimento consentito     48
  # 1 = movimento impedito    49
  # C = movimento limitato da un vincolo cedevole    67
  attr_accessor :sx
  attr_accessor :sy
  attr_accessor :rz
  # costante elastica del vincolo alla traslazione lungo x
  attr_accessor :csx
  # costante elastica del vincolo alla traslazione lungo y
  attr_accessor :csy
  # costante elastica del vincolo alla traslazione lungo z
  attr_accessor :csz
  # costante elastica del vincolo alla rotazione attorno x
  attr_accessor :crx
  # costante elastica del vincolo alla rotazione attorno y
  attr_accessor :cry
  # costante elastica del vincolo alla rotazione attorno z
  attr_accessor :crz
  # numero totale di nodi creati
  @@numero_nodi = 0
  # Inizializzazione della classe
  def 
initialize(id,x,y,z,sx,sy,sz,rx,ry,rz,csx=0,csy=0,csz=0,crx=0,cry=0,crz=0)
    @id = id
    @x = x
    @y = y
    @z = z
    @sx = sx
    @sy = sy
    @sz = sz
    @rx = rx
    @ry = ry
    @rz = rz

    # Per i gradi di libertà per i quali si è usato C come codice di
    # vincolo, bisogna fornire anche la costante elastica di vincoli
    # cedevoli (kN/m per vincoli allo spostamento kNm per vincoli alla 
rotazione)

    @csx = csx
    @csy = csy
    @csz = csz
    @crx = crx
    @cry = cry
    @crz = crz

    @@numero_nodi +=1
  end
  # Il metodo <em>to_s</em> stampa una tabella con i dati caratteristici
  # del nodo.
  def to_s
    puts "\n"
    puts "NODO n. #{@id}"
    puts "="*30
    puts "x=     #{@x} [#{$umlungh}]"
    puts "y=     #{@y} [#{$umlungh}]"
    puts "z=     #{@z} [#{$umlungh}]"
    puts "sx=     #{@sx}"
    puts "sy=     #{@sy}"
    puts "sz=    #{@sz}"
    puts "rx=    #{@rx}"
    puts "ry=    #{@ry}"
    puts "rz=     #{@rz}"
    if not nodo.csx==0
      puts "csx=     #{@csx} [#{$umcedevol}]"
    end
    if not nodo.csy==0
      puts "csy=     #{@csy} [#{$umcedevol}]"
    end
    if not nodo.csz==0
      puts "csz=     #{@csz} [#{$umcedevol}]"
    end
    if not nodo.crx==0
      puts "crx=     #{@crx} [#{$umcedevolrot}]"
    end
    if not nodo.cry==0
      puts "cry=     #{@cry} [#{$umcedevolrot}]"
    end
    if not nodo.crz==0
      puts "crz=     #{@crz} [#{$umcedevolrot}]"
    end
  end
end

# La classe Asta crea una asta tra due nodi.
# I parametri accettati sono:
# id = numero identificativo asta [intero]
# ni = nodo iniziale [intero]
# nf = nodo finale [intero]
# nmat = indice del materiale dell'asta [intero]
# nsez = indice della sezione dell'asta [intero]
# tipo = codice indentificativo del tipo di asta:
#      T = trave alla DeSaint Venant
#      TR = trave alla De saint Venant con tratti rigidi
#      W = trave di fonazione alla Winkler
#      WR = trave di fondazione alla Winkler con tratti rigidi
# *opz = lista di 2 o 4 valori numerici che possono essere:
#      se tipo = TR oppure WR:
#        l1 = lunghezza tratto rigido al nodo ni
#        l2 = lunghezza tratto rigido al nodo nf
#      se tipo = W oppure WR:
#        lb = larghezza sottobase [cm]
#        kw = costante sottofondo [N/cm3]
class Asta
  attr_accessor :id, :ni, :nf, :nmat, :nsez, :tipo, :l1, :l2, :lb, :kw
  @@numero_aste = 0
  def initialize(id,ni,nf,nmat,nsez,tipo,*opz)
    @id=id
    @ni=ni
    @nf=nf
    @nmat=nmat
    @nsez=nsez
    @tipo=tipo
    if @tipo == "TR"
      @l1=opz[0]
      @l2=opz[1]
    elsif @tipo == "W"
      @lb=opz[0]
      @kw=opz[1]
    elsif @tipo == "WR"
      @l1=opz[0]
      @l2=opz[1]
      @lb=opz[2]
      @kw=opz[3]
    end
    @@numero_aste +=1
  end

  # Il metodo <em>to_s/em> stampa una tabella con i dati caratteristici
  # dell'asta.
  def to_s
    puts "\n"
    #puts "="*40
    puts "ASTA n. #{@id}"
    puts "="*50
    puts "nodo i=         #{@ni}"
    puts "nodo f=         #{@nf}"
    puts "materiale n°         #{@nmat}"
    puts "sezione n°         #{@nsez}"
    puts "tipo=          #{@tipo}"
    if @tipo == 'TR' or @tipo == "WR"
      puts "lunghezza tratto rigido al nodo #{@ni}  #{@l1} 
[#{$umlungh}]"
      puts "lunghezza tratto rigido al nodo #{@nf}  #{@l2} 
[#{$umlungh}]"
    end
    if @tipo == "W" or @tipo == "WR"
      puts "Larghezza sottobase lb=     #{@lb} [#{$umlungh}]"
      puts "Costante di sottoforndo kw=     #{@kw} [#{$umdens}]"
    end
  end

  # Il metodo _lungh_ calcolca la lunghezza dell'asta.
  def lungh
    xi = @ni.xi
    yi = @ni.yi
    zi = @ni.zi
    l = Math.sqrt((xf-xi)^2+(yf-yi)^2+(zf-zi)^2)
    return l
  end
end


Nella classe Asta mi serve un metodo che restituisce i tutti i dati dei 
nodi di estrmità: come faccio a "linkare" le due classi?
Posted by Pietro Giorgianni (giorgian)
on 2010-02-06 17:28
(Received via mailing list)
Il 06 febbraio 2010 15.55, Alessandro Barracco <bomastudio@gmail.com>
ha scritto:
> Ho creato due classi:
>
> [...]
>
> Nella classe Asta mi serve un metodo che restituisce i tutti i dati dei
> nodi di estrmità: come faccio a "linkare" le due classi?

Ciao,

Non ho capito, cosa intendi per linkare? Non puoi fare una cosa tipo 
questa?

class Asta
  def dati_dei_nodi_di_estremita
    [@ni.id, @ni.x, @ni.y, ..., @nf.id, @nf.x, @nf.y, ...]
  end
end

O, meglio ancora:

class Nodo
  def dati_del_nodo
    {:x => @x, :y => @y, :z => @z, ...}
  end
end

class Asta
  def dati_dei_nodi_di_estremita
    [@ni.dati_del_nodo, @nf.dati_del_nodo]
  end
end


Spiega meglio cosa intendi.

Ah, una supplica: i byte costano poco, usali! non chiamare le
variabili l1, l2, lb, zi, non ci si capisce niente! Se usi nomi più 
lunghi, risparmi sui commenti.


pietro
Posted by Andrea Dallera (edwin_bolthar)
on 2010-02-06 18:04
(Received via mailing list)
Ciao Alessandro,

  alcune note sparse:

- wrappare le componenti x,y,z di posizione e costanti elastiche.
Qualcosa di questo tipo:

class Vector

  def initialize(x,y,z)
    @x, @y, @z = x, y,z
  end

end

puoi ereditare da Vector nel caso (probabile) in cui ci sia della logica
associata alla posizione/costante elastica.

- quel @@numero_nodi mi piace pochino :-) perchè lo usi? Non vedo niente
nella classe Nodo stessa che ne faccia uso. Se la necessità del counter
è dovuta a qualche altra classe è il caso che sia la classe che ne ha
bisogno ad assumersi la 
responsabilità.
- nel costruttore della classe asta: tipo e opzioni nascondono in realtà 
classi, non passare stringhe in giro e comparare ma crea una classe per
ogni tipo. Qui la logica di dominio non la conosco ma un' idea potrebbe
essere qualcosa del genere:

class Trave
  #logica per le travi
end

class DeSaint < Trave
  #logica per le travi desaint
end

class Winkler < Trave
  #logica per le travi winkler
end

e via così. Se la logica per le travi rigide è comune per tutte le travi
puoi anche creare un modulo (esempio)

module TraveRigida
 #logica per le travi rigide
end

ed includerlo dove serve:

class WinklerRigida < Trave
  include TraveRigida

end

- non passare in giro l'ID per identificare i nodi: se non ti serve per
altre esigenze (tipo persistenza in DB) eliminalo, e passa in giro
direttamente le istanze.

- stessa cosa per nmat e nsez: fai delle classi e passa in giro le
istanze, tipo:

class Materiale
  #logica comune a tutti i materiali
end

class MaterialeFoo < Materiale
  #logica
end

in questo caso dipende però da quanti materiali hai e da quanto varia la
logica fra uno e l'altro: se sono tanti e tutti uguali allora usa solo
una classe materiale, se ne hai logiche diverse per materiali diversi
fai classi diverse. Stesso discorso per le sezioni

- il costruttore di asta diventerebbe

def TraveCippaLippa < Trave

  #usa nomi significativi per le variabili... li paghi te i
caratteri? :-)
  def initialize(nodo_iniziale, nodo_finale, materiale, sezione)

    @nodo_iniziale = nodo_iniziale
    @nodo_finale   = nodo_finale
    @materiale     = materiale
    @sezione       = sezione
    # niente @@numero_aste += 1, stesso discorso che per i nodi

  end

HTH!

--
Andrea Dallera
http://usingimho.wordpress.com
Posted by Alessandro Barracco (bomastudio)
on 2010-02-06 19:50
Grazie Pietro per la rapidità .

> Spiega meglio cosa intendi.

Creo 100 nodi, da 1 a 100.
Creo 60 aste.
Ad esempio l'asta 23 ha come nodi il numero 44 e il numero 87.

nodo44 = Nodo(0,0,0,...)
nodo87 = Nodo(100,0,0, ....)

asta23 = Asta(44,87,......)


Vorrei scrivere qualcosa del tipo:

puts "Il nodo iniziale dell'asta 23 ha coordinate"
puts asta23.nodo_iniziale.x
puts asta23.nodo_iniziale.y
puts asta23.nodo_iniziale.z



> Ah, una supplica: i byte costano poco, usali! non chiamare le
> variabili l1, l2, lb, zi, non ci si capisce niente! Se usi nomi pi� 
lunghi, risparmi sui commenti.
> 

Si vero, ma:

1) quando avrò a che fare con delle formule un conto è scrivere

q = (l1^2 + l2^2)*sqrt(....)

un'altro è scrivere

carico_per_metro_lineare_asta = (lunghezza_1^2 + 
lunghezza_2^2)*sqrt(.....

:-)

2) I commenti li uso perchè voglio utilizzare rdoc, ..... :-)
Posted by Alessandro Barracco (bomastudio)
on 2010-02-06 19:59
Grazie Andrea.

> - wrappare le componenti x,y,z di posizione e costanti elastiche.
> Qualcosa di questo tipo:
> 
> class Vector
> 
>   def initialize(x,y,z)
>     @x, @y, @z = x, y,z
>   end
> 
> end
> 
> puoi ereditare da Vector nel caso (probabile) in cui ci sia della logica
> associata alla posizione/costante elastica.

Cosa vuol dire "wrappare"?

> - quel @@numero_nodi mi piace pochino :-) perch� lo usi? Non vedo niente
> nella classe Nodo stessa che ne faccia uso. Se la necessit� del counter
> � dovuta a qualche altra classe � il caso che sia la classe che ne ha
> bisogno ad assumersi la 
> responsabilit�.

OK

- nel costruttore della classe asta: tipo e opzioni nascondono in realt�
classi, non passare stringhe in giro e comparare ma crea una classe per
> ogni tipo. Qui la logica di dominio non la conosco ma un' idea potrebbe
> essere qualcosa del genere:
> 
> class Trave
>   #logica per le travi
> end
> 
> class DeSaint < Trave
>   #logica per le travi desaint
> end
> 
> class Winkler < Trave
>   #logica per le travi winkler
> end
> 
> e via cos�. Se la logica per le travi rigide � comune per tutte le travi
> puoi anche creare un modulo (esempio)
> 
> module TraveRigida
>  #logica per le travi rigide
> end
> 
> ed includerlo dove serve:
> 
> class WinklerRigida < Trave
>   include TraveRigida
> 
> end

Mi sembra decisamente più razionale :-)


> - non passare in giro l'ID per identificare i nodi: se non ti serve per
> altre esigenze (tipo persistenza in DB) eliminalo, e passa in giro
> direttamente le istanze.


Dato che dovrò gestire centinaia di nodi e di aste (ma non di sezioni e 
materiali) pensavo ad un DB. Non so, cosa consigli?

> - stessa cosa per nmat e nsez: fai delle classi e passa in giro le
> istanze, tipo:
> 
> class Materiale
>   #logica comune a tutti i materiali
> end
> 
> class MaterialeFoo < Materiale
>   #logica
> end
> 
> in questo caso dipende per� da quanti materiali hai e da quanto varia la
> logica fra uno e l'altro: se sono tanti e tutti uguali allora usa solo
> una classe materiale, se ne hai logiche diverse per materiali diversi
> fai classi diverse. Stesso discorso per le sezioni

Scusa la (ennesima) domanda da 'negozio degli orrori':::
Come faccio a passare una istanza al posto dell'id?

> - il costruttore di asta diventerebbe
> 
> def TraveCippaLippa < Trave
> 
>   #usa nomi significativi per le variabili... li paghi te i
> caratteri? :-)
>   def initialize(nodo_iniziale, nodo_finale, materiale, sezione)
> 
>     @nodo_iniziale = nodo_iniziale
>     @nodo_finale   = nodo_finale
>     @materiale     = materiale
>     @sezione       = sezione
>     # niente @@numero_aste += 1, stesso discorso che per i nodi
> 
>   end

Già detto a Pietro.

Grazie davvero per gli utilissimi consigli.

Posted by Andrea Dallera (edwin_bolthar)
on 2010-02-06 20:39
(Received via mailing list)
On Sat, 2010-02-06 at 19:59 +0100, Alessandro Barracco wrote:
> > 
> > end
> > 
> > puoi ereditare da Vector nel caso (probabile) in cui ci sia della logica
> > associata alla posizione/costante elastica.
> 
> Cosa vuol dire "wrappare"?

Giusta osservazione :-) avrei dovuto spiegarmi nel dettaglio.
Nel tuo caso hai come parametri nel costruttore, fra gli altri, x y e z.
Insieme rappresentano la posizione del nodo. Se, invece di passarli come
valori numerici che, in linea teorica, potrebbero anche essere
interpretati come non collegati l'uno all' altro costruisci una classe
(la suddetta Vettore) che li contiene è come se tu dicessi "ok, questi
valori x y e z non sono semplici valori numerici ma, insieme,
costituiscono una entità vettore che rappresenta un punto nello spazio".
Nel caso ti servisse, ad esempio, di avere il vettore in un sistema di
coordinate polari potresti aggiungere un metodo nella classe vettore che
si occupa della conversione.
> classi, non passare stringhe in giro e comparare ma crea una classe per
> > 
> > 
> > - non passare in giro l'ID per identificare i nodi: se non ti serve per
> > altre esigenze (tipo persistenza in DB) eliminalo, e passa in giro
> > direttamente le istanze.
> 
> 
> Dato che dovrò gestire centinaia di nodi e di aste (ma non di sezioni e 
> materiali) pensavo ad un DB. Non so, cosa consigli?

Salvare in DB ha senso ma non creare cose che non ti servono prima del
tempo. Se e quando deciderai di persistere il tuo grafo di oggetti in un
database allora potrai pensare ad aggiungere id e cose del genere.
> > end
> > 
> > in questo caso dipende per� da quanti materiali hai e da quanto varia la
> > logica fra uno e l'altro: se sono tanti e tutti uguali allora usa solo
> > una classe materiale, se ne hai logiche diverse per materiali diversi
> > fai classi diverse. Stesso discorso per le sezioni
> 
> Scusa la (ennesima) domanda da 'negozio degli orrori':::
> Come faccio a passare una istanza al posto dell'id?

esempio:

start     = Nodo.new
end       = Nodo.new
materiale = Materiale.new
sezione   = Sezione.new
trave     = Trave.new(start, end, materiale, sezione)

puoi passare come parametro un oggetto esattamente nello stesso modo in
cui passi in giro un fixnum o una stringa. In ruby tutto (o quasi :)) è
un oggetto, dal punto di vista delle "variabili" non fa differenza se si
tratta di un numero (istanza della classe Fixnum) o dell' istanza di una
classe da te creata.
> >     @nodo_finale   = nodo_finale
> 
--
Andrea Dallera
http://usingimho.wordpress.com
Posted by Pietro Giorgianni (giorgian)
on 2010-02-06 21:47
(Received via mailing list)
Il 06 febbraio 2010 19.50, Alessandro Barracco <bomastudio@gmail.com>
ha scritto:
>
> un'altro è scrivere
>
> carico_per_metro_lineare_asta = (lunghezza_1^2 +
> lunghezza_2^2)*sqrt(.....
>
> :-)
>
> 2) I commenti li uso perchè voglio utilizzare rdoc, ..... :-)

1)
Immagino che i calcoli vorrai concentrarli in (relativamente) pochi
metodi; lì (e solo lì) puoi eventualmente usare variabili:

def primo_calcolo_astruso
  l = una_lunghezza_con_un_nome_comprensibile
  q = una_quantita_di_cui_non_so_nulla
  c = non_voglio_nemmeno_saperlo

  (l * q + c) ** 3 - ...
end

2)
Non ti sto suggerendo di eliminare tutti i commenti, solo quelli 
dannosi.

Considera che, se tutto va bene, quasi nessuna delle righe di codice
che scrivi sopravviverà: man mano che aggiungi, togli, riorganizzi,
riscriverai tutto più e più volte.

Mantenere attuali i commenti raddoppierà il lavoro; se una volta ti
dimenticherai di aggiornare un commento, il codice diventerà un
labirinto.


Se i commenti servono a spiegare cosa fa il codice, vuol dire che il
codice non è chiaro.

I commenti dovrebbero spiegare *perché* il codice fa quello che fa; ad
esempio, nel caso del tuo progetto, i commenti sono indispensabili, ma
dovrebbero riguardare in massima parte i concetti trattati dal codice,
cioè Asta, Nodo, traslazione, rotazione etc.


pietro
Please log in before posting. Registration is free and takes only a minute.
Existing account (Switch to SSL-encrypted connection)
NEW: Do you have a Google/GoogleMail or Yahoo account? No registration required!
Log in with Google account | Log in with Yahoo account
No account? Register here.