>>>>> "MikkelFJ" == MikkelFJ <mikkelj-anti-spam / post1.dknet.dk> writes:
MikkelFJ> Are there interfaces in Ruby? If not, why not?
MikkelFJ> However, I would like to be able to query an object
MikkelFJ> about an interface, such that I know I can trust it to
MikkelFJ> do the expected.
MikkelFJ> shape_collection.each do |obj|
MikkelFJ> case obj
MikkelFJ> when IRayIntersection
MikkelFJ> clip_using_interface(obj)
MikkelFJ> when Box
MikkelFJ> clip_as_rectangle(obj)
MikkelFJ> when Sphere
MikkelFJ> clip_as_circle(obj)
MikkelFJ> end
MikkelFJ> end
Assuming the choice of clipping algorithm rests solely in the type of
Shape, then moving the clipping algorithm into the shape objects make
a lot of sense. Then your code will look like ...
shape_collection.each { |shape| shape.clip }
If a BoxWithHole can't use the standard box algorithm, it will
implement the IRayIntersection algorithm for its version of clip. No
need to search a list of possible algorithms. Best of all, if you add
a new algorithm there is no need to update this case statement (and
any others you might have).
On the other hand, it is possible that the choice of clipping
algorithm is dependent upon both the sender and receiver. In other
words, clipping a box against a box is different than clipping a
circle against a box, which in turn is different from circle/circle
clipping. This is a tougher problem.
One possibility is using a double dispatch setup like this (sorry
about the long example) ...
# START CODE ---------------------------------------------------------
module ClippingAlgorithms
def box_circle_clip(box, circle)
puts "Box/Circle Clipping"
end
def circle_circle_clip(circle1, circle2)
puts "Circle/Circle Clipping"
end
def box_box_clip(box1, box2)
puts "Box/Box Clipping"
end
end
class Circle
include ClippingAlgorithms
def clip(other)
other.circle_clip(self)
end
def circle_clip(circle)
circle_circle_clip(self, circle)
end
def box_clip(box)
box_circle_clip(box, self)
end
end
class Box
include ClippingAlgorithms
def clip(other)
other.box_clip(self)
end
def circle_clip(circle)
box_circle_clip(self, circle)
end
def box_clip(box)
box_box_clip(self, box)
end
end
b = Box.new
c = Circle.new
b.clip(b) #=> Box/Box Clipping
c.clip(c) #=> Circle/Circle Clipping
b.clip(c) #=> Box/Circle Clipping
c.clip(b) #=> Box/Circle Clipping
# END CODE -----------------------------------------------------------
The downside is that adding new shapes causes an explosion of new
combinations. Sometimes this can be mitigated through judicious use
of inheritance.
If you don't need the complexity, obviously the first solution is much
better.
--
-- Jim Weirich jweirich / one.net http://w3.one.net/~jweirich
---------------------------------------------------------------------
"Beware of bugs in the above code; I have only proved it correct,
not tried it." -- Donald Knuth (in a memo to Peter van Emde Boas)