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 ( child.parent.update
).
I'd like one object (which could be thought of as a child-but-not-child-because-this-isn't-inheritance) to be passed a reference to another object when it is initialized. I'd compare this to a parent child relationship in a database where we store info on the parent so we don't have to duplicate it onto every child.
Example:
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
The above code does work, but is there a better (more concise, or more ruby-esq) way to achieve this?
Thanks so much for your help/thoughts.
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 , ie 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)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.