[Nitro] Encapsulation (was Re: xhtml builder in model?)

Ysabel deb at ysabel.org
Wed Sep 7 09:56:09 EDT 2005

>>   class Writer
>>     def render( model )
>>       do_this(model.x)
>>       do_that(model.y)
>>   class Model
>>      def render( writer )
>>          writer.do_this(self.x)
>>          writer.do_that(self.y)
> I don't know that I can offer a persuasive argument, but I prefer the
> latter.

The former violates encapsulation (Writer knows that model has properties X 
and Y, and if you change the general shape of Model, you'll have to change 
Writer as well).  The latter does not, presuming that do_this() and 
do_that() are, in fact, intended as part of Writer's public interface and 
thus less likely to change.

To make it more concrete, since do_this and do_that don't tell you much, 

  class Model
    attr_accessor :name
    attr_accessor :color

    def self.color_choices
      [ "Red", "Green", "Blue" ]

  class Writer
    def render_text_input(value)
    def render_choice(value)
    def render(model)
      render_choice(model.color, Model.color_choices)

to this:

  class Writer
    def render_text_input(value)
    def render_choice(value)

  class Model
    def render(writer)
      writer.render_choice(@color, ["Red", "Green", "Blue"])

When looking at those two cases, ask the question about which objects know 
what things.  Encapsulation is all about keeping knowledge on a 
need-to-know basis.  Yes, the code for these two isn't all that different, 
but in the first case Writer knows about Model's implementation -- it knows 
that Models have names and colors and that names should be rendered as text 
and colors should be rendered as choices, and it has to know how to figure 
out what the valid choices for a color are; in the second only Model knows 
how it's implemented (and the details aren't even exposed).  In the first, 
Model doesn't know anything at all about Writer; in the second, Model knows 
that Writer allows one to render a text input and a choice, but nothing 

This is, of course, based on the assumption that Writer has a well-defined 
interface and it's most likely Model that you're planning on tweaking as 
you work through the problem.  If Writer is not well-defined, then both of 
the original examples violate encapsulation by messing with each other's 
implementation details...and you really need to figure out some sort of 
stable interface!  Or at least a metastable one...note also that I am using 
interface in a generic sense here rather than in some sort of strict-typing 
capital-I-Interface sense.

This is not unique to Ruby somehow; it's a standard problem in every 
language I've ever worked in, though the idiomatic solution may change from 
language to language.  Reducing coupling and increasing coherency (and 
defining which is which) is an issue even in non-OO languages like, oh, C 
or assembly.  :)

[ deb at ysabel.org ]          - Ysabel -          [ http://www.ysabel.org/ ]

More information about the Nitro-general mailing list