2013-01-21 10 views
7

Sto chiedendo aiuto per quanto riguarda un modello di progettazione. Sono molto abituato alle interfacce in java e non so come ottenere un meccanismo simile in ruby. Ciò di cui ha bisogno è un tipo di interfaccia che ha un metodo, ad es. contatti. Per ottenere contatti ho bisogno di fare una chiamata contro un'api, questo potrebbe essere google, linkedid o qualsiasi servizio web. Quindi mi piacerebbe usare un'interfaccia che mi fornisce il metodo dei contatti e non voglio sapere nulla del provider oltre.modello di disegno interfacciale in rubino

Il mio primo tentativo simile a questa (pseudo codice):

Module AbstractContact 
def contacts 
    #do some stuff with @data 
    @data 
end 
end 

class Impl 
    include AbstractContact 
def build_provider(provider) 
    if provider == :google 
    #get the data from google 
    gdata= api_call 
    @data = gdata 
    elsif provider == :linkedin 
    end 
end 
end 


c=Impl.new 
c.build_provider 

c.contacts 

Ma io non sono proprio sicuro, se questo è il "modo ruby ​​andare".

Aiuto, suggerimenti e consigli sono benvenuti. Best, Phil

+0

Eventuali duplicati: http://stackoverflow.com/questions/ 4437291/what-is-java-interface-equivalent-in-ruby – BentOnCoding

+0

usa l'ereditarietà e fa in modo che la funzione generi un errore nella classe genitore. – oldergod

risposta

2

I moduli vengono in genere utilizzati per escludere il comportamento comune di più oggetti. Credo che tutto ciò che ti serve in questo caso sia la tipizzazione delle anatre. È sufficiente implementare il metodo contacts in tutte le classi che condividono l'interfaccia nella soluzione Java.

Si prega di notare che questa soluzione consente di conservare oggetti di tipi diversi in una singola raccolta e mentre si itera su di essi (o in qualsiasi altro modo si desidera utilizzare questi oggetti con interfaccia comune) basta chiamare questo contacts metodo, non preoccuparsi di che tipo sono veramente.

Se è necessario un comportamento comune in tutte le classi che implementano questa interfaccia, è possibile creare un modulo basato sull'esistenza del metodo contacts e includerlo in tutte le classi che potrebbero utilizzarlo.

4

Ci sono molti buoni approcci a questo. Uno è quello di incapsulare le diverse funzionalità in moduli:

module Google 
    def contacts 
    puts 'contacts from Google' 
    end 
end 

module LinkedIn 
    def contacts 
    puts 'contacts from LinkedIn' 
    end 
end 

class Impl 
    def self.create provider 
    o = new 
    o.extend(provider) 
    end 
end 

Impl.create(Google).contacts 
Impl.create(LinkedIn).contacts 

uscita:

contacts from Google 
contacts from LinkedIn 

Qui il metodo create su Impl è un metodo factory per le istanze IMPL che aggiunge nei metodi dal modulo dato. Assicurati solo che i moduli implementino gli stessi nomi dei metodi e restituiscano valori compatibili.

+0

bel approccio! – dc10

4
modello

strategia potrebbe essere applicata qui

def Provider 
    def contacts 
    raise "Abstract method called" 
    end 
end 

class Google < Provider 
    def contacts 
    data = # Google API call 
    end 
end 

class LinkedIn < Provider 
    def contacts 
    data = # LinkedIn API call 
    end 
end 

class Impl 
    def initialize(provider) 
    case provider 
    when :google 
     @provider = Google.new 
    when :linkedin 
     @provider = LinkedIn.new 
    else 
     raise "Unknown provider" 
    end 
    end 

    def contacts 
    @provider.contacts 
    end 
end 

impl = Impl.new(provider) 
impl.contacts 
1

mi piace molto la risposta @Bui del Hoa, ma io aggiungere il seguente:

Mi piace questo approccio molto, soprattutto l'innalzamento del errore nella classe del provider di base. Comunque non penso che avere la dichiarazione del caso in Impl sia un buon uso del modello di strategia. Viola il principio di un unico scopo in quanto rende l'implementazione responsabile per tenere traccia di tutti i possibili provider. Inoltre viola il principio di open-close delle classi aperte all'estensione, ma non le modifiche, perché quando si aggiunge un nuovo provider è necessario modificare la dichiarazione del caso.

Perché non solo fare

impl = Impl.new(Google.new) 

Dal momento che l'aumento "fornitore sconosciuto" errore sarebbe preso cura di questo modo:

impl = Impl.new(BadProvider.new) => Error