Devo preferire i metodi di istanza ai metodi di classe in Ruby?

4

Sto lavorando su un'applicazione di rails e sto estraendo funzionalità dal mio codice di rails e in classi di ruby pure in lib /. Mi sono trovato spesso a scrivere lezioni come questa:

 class MailchimpIntegration   
  def subscribe_email(email, fname, lname)
    Gibbon.list_subscribe(:id => NEWSLETTER_LIST_ID, :email_address => email,
      :merge_vars => {'fname' => fname, 'lname' => lname },
      :email_type => "html",  :double_optin => false, :send_welcome => false)
  end

  def unsubscribe_email(email)
    Gibbon.list_unsubscribe(:id => NEWSLETTER_LIST_ID, :email_address => email)
  end

  def change_details(old_email, email, fname, lname)
    Gibbon.list_update_member(:id => NEWSLETTER_LIST_ID, :email_address => old_email,
      :merge_vars => {'email' => email, 'fname' => fname, 'lname' => lname })
  end

  def get_email_info(email)
    Gibbon.list_member_info(:id => NEWSLETTER_LIST_ID, :email_address => [email])["data"].first
  end
end

La mia domanda è: dovrei cambiare questi metodi per essere metodi di classe?

Sembra ragionevole farlo, poiché probabilmente finirò per chiamarli semplicemente aggiornando ogni volta una classe MailchimpIntegration. Tuttavia, in genere preferisco avere metodi di istanza in quanto possono essere più facilmente eliminati, ecc., Anche se questo sembra essere un problema minore in ruby.

Ho diverse classi come questa nel mio sistema, quindi sarei desideroso di vedere cosa ne pensa la gente.

    
posta Jords 26.08.2012 - 11:21
fonte

2 risposte

3

Un altro approccio che puoi fare è usare i mixin.

    module InteractsWithMailChimp
       def subscribe_email(email, fname, lname)
          Gibbon.list_subscribe(:id => NEWSLETTER_LIST_ID, :email_address => email, 
          :merge_vars => {'fname' => fname, 'lname' => lname }, 
          :email_type => "html",  :double_optin => false, :send_welcome => false)
       end
    end

    Class User
        include InteractsWithMailChimp
    end

Questo approccio ti darebbe il vantaggio di avere / utilizzare variabili di istanza dal contesto dell'utente all'interno del modulo. Il modulo può essere testato isolatamente estendendolo all'interno di ogni caso di test. All'interno del modulo è possibile separare le responsabilità, ad esempio si può considerare che la parte di iscrizione / annullamento della sottoscrizione è di per sé una responsabilità in modo da avere:

    module InteractsWithMailChimp
       class HandlesSubscriptions
           def subscribe_email(email, fname, lname)
              Gibbon.list_subscribe(:id => NEWSLETTER_LIST_ID, :email_address => email, 
              :merge_vars => {'fname' => fname, 'lname' => lname }, 
              :email_type => "html",  :double_optin => false, :send_welcome => false)
           end
       end
    end

    Class User
        include InteractsWithMailChimp::HandlesSubscriptions
    end

All'interno delle classi che fanno parte del modulo se si considera che non si avranno bisogno di dati esterni non vi è alcun problema nel rendere i metodi di classe. Mi piace l'approccio mixin in più perché è semplice da riutilizzare, non ha bisogno di ripetersi con l'istanza dell'oggetto e posso nominare i miei moduli e le classi all'interno dei moduli facendo riferimento esattamente alla responsabilità che hanno. Manterò comunque questi moduli separati in / lib ovviamente. Per ulteriori suggerimenti e trucchi davvero utili su come organizzare il codice dei binari e far eseguire rapidamente il test, puoi consultare i test dei binari rapidi . Spero che sia d'aiuto.

    
risposta data 26.08.2012 - 15:44
fonte
0

Sto inserendo questo come risposta, dato che potrei sbagliarmi, ma penso di avere una buona ragione per andare con i metodi di istanza rispetto ai metodi di classe in questo caso.

La classe mailchimp sopra viene chiamata dalla classe User quando l'utente viene salvato, modificato via email, ecc., mi resi conto che dovevo assicurarmi di non chiamare l'API mailchimp in test, altrimenti tutti i miei test saranno super lenti . (Escludo la roba del mailchimp nei test che lo riguardano, ma non lo faccio per gli altri test che riguardano solo l'utente).

Con i metodi di classe, sembra che sarebbe un problema dal momento che non posso cancellare facilmente tutti i metodi, ma con gli oggetti MailchimpIntegration, posso solo inserire:

  def mailchimp
    if Rails.env.production?
      MailchimpIntegration.new
    else
      NullObject.new
    end
  end

Nella mia classe utente, e lo stub per restituire il mio oggetto stub, sto testando l'integrazione.

    
risposta data 26.08.2012 - 12:55
fonte

Leggi altre domande sui tag