Search code examples
c#rubydesign-patternsdynamic-languages

preferred way to implement visitor pattern in dynamic languages?


As an exercise for myself, I was translating a sample program into various languages. Starting in C#, I had a visitor-pattern interface like so:

interface Visitor
    {
        void Accept(Bedroom x);
        void Accept(Bathroom x);
        void Accept(Kitchen x);
        void Accept(LivingRoom x);
    }

Moving to ruby (or python, or whatever), I no longer get dispatch from the compiler based on type. Should I do the dispatch in the visitor itself?

class Cleaner

  def accept(x)
    acceptBedroom(x) if Bedroom === x
    acceptBathroom(x) if Bathroom === x
    acceptKitchen(x) if Kitchen===x
    acceptLivingRoom(x) if LivingRoom===x
  end

  ...

Or should I do the dispatch in the different specializaions of the room:

class Bathroom<Room
  def initialize(name)
    super(name)
  end
  def accept(visitor)
    visitor.acceptBathroom(self)
  end
end

Or is there another preferred idiom that is used in dynamic languages?


Solution

  • My recommendation is to use the former approach. There are pluses and minuses for each approach. The former is harder to maintain as the number of Room types grows; the latter is harder as the number of Cleaner types grows.

    In Ruby, you could try

    def accept(x)
      send "accept#{x.class}".to_sym, x
    end
    

    PS: not all dynamically typed languages are unable to do dispatch based on type; some can infer type, or failing that, can used forced casting to pick the proper method among the overloaded options.