Let's say I have two classes. One class, "parent", has many of another class "child". This is not inheritance, I don't want parent methods to act on child objects. What I want is the child object to be able to reference the parent object, get variables from it (child.parent.var) and call parent methods that modify the parent (
@var = num
@var += 1
attr_accessor :var, :parent
def initialize(parent, num)
@parent = parent
@var = num
@parent.var + var
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
This is basically how it's supposed to be done :) There are a couple of possible improvements though, depending on what you actually want to achieve.
Right now, your
Child instances expose access to the parent on their external interface (via the public
parent accessor). This is often a violation of the Law of Demeter which states that objects should only talk to their direct neighbors. In this sense, the
parent is a stranger when accessed though the child object.
You could improve your design by hiding the parent object:
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
Here, we use Ruby's Forwardable module to provide access to some methods of the parent from the client. This makes these methods part of the single public interface of your Child class.
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
From the outside, it doesn't matter that the methods are forwarded and you can later change this without affecting your external interface at all.
A second improvement could be to extend your
Parent class to generate children directly:
class Parent # ... def child(num) Child.new(self, num) end end
This is usually called a Factory Method, i.e. a method which builds other objects. With this, you can hide the complexity of building your Child objects and attaching them to your parent.
You can call it like
parent = Parent.new(1) child = parent.child(2)