From: Florian Gross Date: 2005-03-23T11:09:49+09:00 Subject: Re: Any guides for good coding in Ruby? James Edward Gray II wrote: >> It's not a Ruby API design idiom, but anyway (perhaps we should split >> this page in two: Ruby API idioms and design advices). >> >> Classes are supposed to reflect reality. Thus, you should generally >> put your methods where they belong, to reduce coupling. For example, >> typical "data classes" should not have "actions", but methods to >> access their data. >> >> Example: >> # >> # Bad API >> # >> class GraphicElement >> def draw(canvas) >> raise "Implement me!" >> end >> end >> class Circle < GraphicElement >> def draw(canvas) >> # Draw directly into the canvas >> # (couples Circle with the canvas, as Circle >> # follows this particular canvas API) >> end >> end >> >> # >> # Good API (definitely better than above, perhaps not the best) >> # >> class GraphicElement >> def to_canvas(resolution) >> raise "Implement me!" >> end >> end >> class Circle < GraphicElement >> def to_canvas(resolution) >> # Convert circle to an array of arrays of pixels, >> # taking into account the resolution parameter >> end >> end >> class CanvasPainter >> def paint(elmt, canvas, color=Color::BLACK, >> centerX=0, centerY=0) >> elmt.to_canvas.each do |x,y| >> canvas.put(centerX+x, centerY+y, color) >> end >> end >> end > > > I can't decide if it's just the example or the whole section, but this > one just doesn't feel right to me. I would much rather have a class > rendering itself (who better qualified?), then providing accessor like > data for others to do it. Push, don't pull, right? I think this is related to double dispatch. There'll probably be a Surface#draw that takes an object and calls #to_canvas on it. This way both objects can handle part of the drawing contract by meeting in the middle.