2010-04-19 12 views
17

Je travaille actuellement sur le livre Gregory Brown Ruby Best Practices. Au début, il parle de refactoriser certaines fonctionnalités des méthodes d'aide sur une classe liée, à certaines méthodes sur le module, puis a eu le module extend self.Quand utiliser un module et quand utiliser une classe

N'avait pas vu auparavant, après un google rapide, a découvert que extend self sur un module permet de voir les méthodes définies sur le module, ce qui est logique.

Maintenant, ma question est quand voulez-vous faire quelque chose comme ça

module StyleParser 
    extend self 

    def process(text) 
    ... 
    end 

    def style_tag?(text) 
    ... 
    end 
end 

puis faire référence dans les tests avec

@parser = Prawn::Document::Text::StyleParser 

par opposition à quelque chose comme ça?

class StyleParser 

    def self.process(text) 
    ... 
    end 

    def self.style_tag?(text) 
    ... 
    end 
end 

est-ce que vous pouvez l'utiliser comme un mixin? ou y a-t-il d'autres raisons que je ne vois pas?

Répondre

30

Une classe doit être utilisée pour les fonctionnalités qui nécessitent une instanciation ou qui doivent garder une trace de l'état. Un module peut être utilisé comme un moyen de mélanger des fonctionnalités dans plusieurs classes, ou comme un moyen de fournir des fonctionnalités uniques qui n'ont pas besoin d'être instanciées ou de garder une trace de l'état. Une méthode de classe pourrait également être utilisée pour ce dernier. Dans cet esprit, je pense que la distinction réside dans le fait de savoir si vous avez vraiment besoin d'une classe ou non. Une méthode de classe semble plus appropriée lorsque vous avez une classe existante qui a besoin de fonctionnalités singleton. Si ce que vous faites ne consiste qu'en des méthodes singleton, il est plus logique de l'implémenter en tant que module et d'y accéder directement via le module.

+1

Exactement ce que je cherchais :-) –

-2

Si c'est quelque chose que vous voulez instancier, utilisez une classe. Le reste de votre question a besoin de plus de contexte pour avoir du sens.

3

Dans ce cas particulier, je n'utiliserais probablement ni une classe ni un module.

Une classe est une fabrique d'objets (notez le pluriel). Si vous ne souhaitez pas créer plusieurs instances de la classe, il n'est pas nécessaire qu'elle existe.

Un module est un conteneur pour les méthodes, partagé entre plusieurs objets. Si vous ne mélangez pas le module en plusieurs objets, il n'est pas nécessaire qu'il existe.

Dans ce cas, il semble que vous vouliez juste un objet. Il faut donc utiliser un:

def (StyleParser = Object.new).process(text) 
    ... 
end 

def StyleParser.style_tag?(text) 
    ... 
end 

Ou bien:

class << (StyleParser = Object.new) 
    def process(text) 
    ... 
    end 

    def style_tag?(text) 
    ... 
    end 
end 

Mais comme @Azeem déjà écrit: pour une bonne décision, vous avez besoin d'un contexte plus. Je ne suis pas assez familier avec les internes de Prawn pour savoir pourquoi Gregory a pris cette décision particulière.