La Gioia del Delegare

Posted by Chiaroscuro, Sat Oct 21 23:30:06 UTC 2006

Se anche voi siete come me, il vecchio libro PikeAxe dei pragmatic programmers che trovate online, rimane la vostra principale reference guide quando volete sapere quali metodi ha una classe o quali classi sono disponibili.

Utilissimo libro, però non copre tutto.. e questo l’ho scoperto frugando tra le lib nella directory di installazione di Ruby.

Tra i vari rubini che ho trovato in quelle directory, forwardable è uno di quelli che più mi ha colpito per la sua utilità.

Se anche voi siete come me, il vecchio libro PikeAxe dei pragmatic programmers che trovate online, rimane la vostra principale reference guide quando volete sapere quali metodi ha una classe o quali classi sono disponibili.

Utilissimo libro, però non copre tutto.. e questo l’ho scoperto frugando tra le lib nella directory di installazione di Ruby.

Tra i vari rubini che ho trovato in quelle directory, forwardable è uno di quelli che più mi ha colpito per la sua utilità. Mettete che avete bisogno di rappresentare un’entità che agisce come contenitore per altre entità. Perchè no, abbozziamo una classe Cassetto!

class Cassetto
end
cassetto_dell_armadio = Cassetto.new
cassetto_dell_armadio << "calzini" 
cassetto_dell_armadio << "maglietta" 
cassetto_dell_armadio << "maglietta"
puts cassetto_dell_armadio

Per ora abbiamo solamente descritto il comportamento della classe, senza specificarne la struttura interna. Notiamo immediatamente che il nostro Cassetto condivide molte caratteristiche della classe Array. Vogliamo poter usare l’operatore << per inserire magliette e calzine e forse più avanti, quando faremo le valige vorremmo anche essere in grado di svuotare i nostri cassetti in una valigia

valigia = cassetto_dell_armadio + cassetto_del_comodino

La tentazione è forte.. lo so che è sbagliato, so che Fowler e Booch piangerebbero a vederlo ma.. eccolo qui:

class Cassetto < Array
end

Il cassetto è un Array! Fatto! Finito!

Me ne volete veramente quando l’alternativa sarebbe stata crare un Array dentro Cassetto e poi delegare tutti i metodi che mi servivano, dolorosamente, uno per uno?

Si lo so, purezza del modello di dominio e tutto quanto, ma anche questo codice è doloroso per gli occhi e straripante di ripetizioni che supplicano di essere estratte

  class Cassetto 
    def initialize
      @vestiti = []
    end      

    def << vestito
       @vestiti << vestito 
    end

    def [] i
      @vestiti[i]
    end

    def first
      @vestiti.first
    end

    ...
    ...

    def to_s
       @vestiti.join "\n" 
    end
  end

In fondo quando dico

def << vestito
  @vestiti << vestito 
end

non sto forse dicendo “delega il metodo << al campo @vestiti” ?

E quando dico

def first
  @vestiti.first
end

non sto forse dicendo “delega il metodo first al campo @vestiti” ?

Quindi forse, quello di cui abbiamo bisogno è un modo sintetico per esprimere proprio questo concetto di delega, evitando così anche la sporca di ereditare direttamente da Array.

Bene, in ruby possiamo utilizzare direttamente forwardable.rb che ci mette a disposizione def_delegators


  class Cassetto
    extend Forwardable      

    def_delegators :@vestiti, :<<, :[], :first, :to_s

    def initialize
      @vestiti = []
    end      

    def to_s
       @vestiti.join "\n" 
    end
  end

  cassetto_dell_armadio = Cassetto.new
  cassetto_dell_armadio << "calzini" 
  cassetto_dell_armadio << "maglietta" 
  cassetto_dell_armadio << "maglietta" 

  puts cassetto_dell_armadio
  puts cassetto_dell_armadio[1]
  puts cassetto_dell_armadio.first

Vediamo che estendendo Fordable e usando def_delegators, possiamo dirottare una serie di metodi (<< [] first to_s) su una attributo di classe, che corrisponde all’array contenitore.

Se dovessimo decidere di non mappare i nomi dei metodi uno a uno tra Cassetto e Array posssiamo usare def_delegator, al singolare, aggiungendo:

def_delegator :@vestiti, :size, :numero_vestiti

e potendo quindi invocare:

puts cassetto_dell_armadio.numero_vestiti

Niente gemme, niente librerie aggiuntive, questo è tutto caro semplice vecchio Ruby!

Filed Under: Linguaggio | Tags:

Comments

Have your say

A name is required. You may use HTML in your comments.