2010-11-02 30 views
7

Quand j'ai lu plus sur la métaprogrammation Ruby, la plupart du temps nous avons trouvé au moins deux solutions pour résoudre un problème. S'il vous plaît consulter deux exemples ci-dessous:Class vs Module dans la conception de Ruby API?

class Base 
    def self.has_many(*args) 
    # ... 
    end 
end 

class Student < Base 
    has_many :books 
end 

Un autre style:

module Base 
    def self.included(klass) 
    klass.extend ClassMethods 
    end 

    module ClassMethods 
    def has_many(*args) 
     # ... 
    end 
    end 
end 

class Student 
    include Base 

    has_many :books 
end 

Mais quand nous concevons api, nous devons décider lequel utiliser, mais je voudrais demander à vos idées et quelques-uns les meilleures pratiques que la plupart des gens ont déjà mises en œuvre dans leurs bibliothèques.

Répondre

5

Si votre API fournit la fonctionnalité de base qui sera prolongée par le client, alors vous devriez préférer héritage.

Si votre API va étendre divers clients avec leurs propres fonctionnalités de base, alors vous devriez opter pour composition.

2

Vous avez beaucoup de théories autour de cette question. J'ai tendance à préférer la composition parce qu'elle rend le comportement beaucoup plus réutilisable, mais si vous regardez Rails, vous devrez sous-classer la classe ActiveRecord :: Base chaque fois que vous voulez un objet dans votre base de données. Si vous regardez DataMapper, c'est le contraire car ils vous demandaient juste d'inclure DataMapper :: Resource. Héritage vs Composition (via des modules) est un sujet important et la question que vous vous poserez sera la suivante: comment puis-je obtenir un plus grand découplage entre les composants que je fournis et un autre code de base existant? Ruby ne prend en charge que l'héritage unique.

1

Par conséquent, si le client API doit hériter de votre classe de base, il perd la possibilité d'hériter d'autres classes. En utilisant l'inclusion de module, vous pouvez créer un code comme:

class Student < Person 
    include Base 
    has_many :books 
end 

Et ainsi vous pouvez "hériter" à la fois de la Personne et de la Base.

Cependant, la syntaxe de l'héritage classique semble plus naturel et moins « magique »