2016-11-15 1 views
4

Disons que j'ai deux classes. Une classe, "parent", a beaucoup d'une autre classe "enfant". Ce n'est pas l'héritage, je ne veux pas que les méthodes parentes agissent sur les objets enfants. Ce que je veux, c'est que l'objet enfant puisse référencer l'objet parent, en obtenir des variables (child.parent.var) et appeler des méthodes parentes qui modifient le parent (child.parent.update). Je voudrais qu'un objet (qui pourrait être considéré comme un enfant-mais-pas-enfant-parce-que-ce-n'est-pas-héritage) soit passé une référence à un autre objet quand il est initialisé. Je compare cela à une relation parent-enfant dans une base de données où nous stockons des informations sur le parent afin que nous ne devions pas le dupliquer sur chaque enfant."Parent", "Enfant" Classes en rubis (pas d'héritage)

Exemple:

class Parent 
    attr_accessor :var 

    def initialize(num) 
    @var = num 
    end 

    def increase 
    @var += 1 
    end 
end 

class Child 
    attr_accessor :var, :parent 

    def initialize(parent, num) 
     @parent = parent 
     @var = num 
    end 

    def sum 
     @parent.increase 
     @parent.var + var 
    end 
end 

parent1 = Parent.new(1) 

child1 = Child.new(parent1, 2) 
child2 = Child.new(parent1, 3) 

child1.parent.increase # update the parent variable 
child2.parent.var  # get the parent variable 

Le code ci-dessus fonctionne, mais est-il une meilleure (plus concis, plus ou rubis Esq) façon d'y parvenir?

Merci beaucoup pour votre aide/pensées.

+0

Bienvenue sur Stack Overflow. C'est une très bonne première question. À l'avenir, essayez de décrire un peu plus les détails de votre problème. "Cela semble étrange" est une description assez vague. Cela étant dit, alors que Stack Overflow tend vers des questions de code dur ces derniers temps, les questions de conception et de structure de code sont toujours abordées ici. Assurez-vous simplement de décrire votre problème réel. Souvent, http://softwareengineering.stackexchange.com/ ou http://codereview.stackexchange.com/ sont d'excellents endroits pour ce genre de questions aussi. –

+0

@HolgerJuste lors de la référence d'autres sites, il est souvent utile de souligner que [cross-posting est désapprouvé] (http://meta.stackexchange.com/tags/cross-posting/info) – gnat

+0

@HolgerJe vous remercie de votre sagesse mon ami! Encore un débutant donc je vais prendre votre avis sur la question suivante :-) –

Répondre

3

Voici à peu près comment cela doit être fait :) Il y a quelques améliorations possibles, en fonction de ce que vous voulez vraiment réaliser.

À l'heure actuelle, vos instances Child exposent l'accès au parent sur leur interface externe (via l'accesseur public parent). Ceci est souvent une violation du Law of Demeter qui stipule que les objets devraient seulement parler à leurs voisins directs. En ce sens, le parent est un étranger lorsqu'on accède à l'objet enfant.

Vous pouvez améliorer votre conception en se cachant l'objet parent:

class Child 
    extend Forwardable 

    def_delegator :@parent, :var, :parent_var 
    def_delegator :@parent, :increase 

    attr_accessor :var 

    def initialize(parent, num) 
    @parent = parent 
    @var = num 
    end 

    def sum 
    @parent.increase 
    @parent.var + var 
    end 
end 

Ici, nous utilisons le module Forwardable de Ruby pour donner accès à certaines méthodes de la société mère du client. Cela fait partie de ces méthodes de l'interface publique unique de votre classe Child.

parent = Parent.new(1) 

child = Child.new(parent, 2) 

child.var 
# => 2 
child.parent_var 
# => 1 
child.increase 
# => 2 
parent.var 
# => 2 
# ^^^^ the increase method was called on the parent object 

De l'extérieur, peu importe que les méthodes sont transmises et vous pouvez changer plus tard cela sans affecter votre interface externe du tout.


Une deuxième amélioration pourrait être d'étendre votre Parent classe pour générer directement les enfants:

class Parent 
    # ... 

    def child(num) 
    Child.new(self, num) 
    end 
end 

Ceci est habituellement appelé Factory Method, à savoir une méthode qui construit d'autres objets. Avec cela, vous pouvez masquer la complexité de la construction de vos objets enfants et de les attacher à vos parents.

Vous pouvez l'appeler comme

parent = Parent.new(1) 
child = parent.child(2)