SitePoint Sponsor

User Tag List

Results 1 to 16 of 16
  1. #1
    Non-Member coo_t2's Avatar
    Join Date
    Feb 2003
    Location
    Dog Street
    Posts
    1,819
    Mentioned
    1 Post(s)
    Tagged
    1 Thread(s)

    observer vs visitor

    So I've been reading this article ( http://devzone.zend.com/node/view/id/9) and was
    wondering some things about the visitor pattern and also what the precise differences
    are between the observer and the visitor.

    I know there's a difference and I'm pretty sure I understand both patterns(at least the observer, because it's simple).


    But it would be nice to have a sort of "formal" summary of the differences.

    I'll list my thoughts about each and you can tell me what's right and wrong:

    Visitor:
    * is "injected" into an object and can be used as a means of providing the target with an implementation
    * target probably only needs to know one method name of the visitor(visit())
    * internally, visitors are able to use the complete public interface of their targets


    Observer:
    * good for one-to-many relationships between objects
    * has a less intimate relationship with its "target"(the observed)
    * doesn't provide an implementation for the target but just reacts to events



    Do these sound OK? Is there anything you would add or subtract to each?


    A few more questions:

    When you implement a visitor, are you also necessarily implementing a strategy pattern? Since each individual
    visitor could be seen as a "strategy" in and of itself.


    What about plugins(not the Fowler definition)? The visitor seems tailor made for plugins. (and maybe even the observer to a lesser extent)


    Do you have or know of any examples of the visitor pattern that doesn't involve a composite structure?

  2. #2
    SitePoint Guru
    Join Date
    Aug 2005
    Posts
    986
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    If you know other languages, this description might help you (it is the clearest for me at least):

    Visitor lets you dispatch on two arguments instead of one. You define a different method for different types of the first argument (the implicit self/this), AND for the second argument (the first if you dont count the implicit self/this). In the article's example: it lets you choose a different method for each node type, and for each list type. You could think of a Visitor as a strategy which is chosen based on the type of the thing you use.

    Observer is a simply a lambda which you call to notify something. A little like aspect oriented programming. Or in OOP terms, an observer is something you notify if you do something. If you do A, you say to the observer: "I'm doing A now", so he can do things you don't want to worry about.

    But if you don't know what multiple dispatch is, or what a lambda is, this will probably be less clear than the description you gave.

    I don't know what you mean by plugins, can you give an example?
    Last edited by Fenrir2; May 27, 2006 at 13:11.

  3. #3
    Non-Member coo_t2's Avatar
    Join Date
    Feb 2003
    Location
    Dog Street
    Posts
    1,819
    Mentioned
    1 Post(s)
    Tagged
    1 Thread(s)
    Quote Originally Posted by Fenrir2
    But if you don't know what multiple dispatch is, or what a lambda is, this will probably be less clear than the description you gave.
    I don't know what multiple dispatch is(but I'll read about it) and I thought a lambda was just an anonymous function?


    I don't know what you mean by plugins, can you give an example?
    Well, I wasn't really sure what I meant. I've been rolling around ideas in my head for implementing a plugin
    api in an app that uses a simple little mvc-like framework somewhat similar to mojavi(most of your app code gets executed inside an "Action"). So I was thinking
    each "Action" would trigger certain events and would call the event handler of each plugin that
    has registered with that particular action.
    But now that I've actually typed out some code(it's still just a fuzzy idea) I see what I was thinking is probably more observer than visitor or maybe a weird visitor/observer hybrid(or maybe neither ).


    PHP Code:
      
      <?php
      
      
    class Plugin {
      
          function 
    handleEvent($eventName$data) {
              
    $method "handle_".$eventName;
              if (
    method_exists($this$method)) {
                  
    $this->$method($data);
              }
          }
      
          
    // abstract
          
    function handle_inserting_foo($data); 
          
    // abstract
          
    function handle_something_else($data);
      
          
    // ...
      
    }
      
      
      class 
    PluginName extends Plugin {  
      
          
    // blah blah
      
      
    }
      
      
      
      
    $pluginEnabled = new IAmPluginEnabled;
      
    $pluginEnabled->attachPlugin(new Plugin1);
      
    $pluginEnabled->attachPlugin(new Plugin2);
      
    $pluginEnabled->attachPlugin(new Plugin3);
      
    $pluginEnabled->execute(...params...);
      
      class 
    IAmPluginEnabled {
      
        
    // ...
      
      
        
    function execute(...params...)
        {
            
    $foo $input->getFoo();
      
            
    // still not sure of the details on how to pass data around
            // but I reckon the "event handlers" for this event will modify $foo directly
            
    $this->_notifyPlugins('inserting_foo'$foo);
      
            
    $datalayer->insert($foo);
      
      
            
    // ...
      
        
    }
      
        
    // ...
      
        // this method would probably actually be in a parent class
        
    function _notifyPlugins($eventName$data)
        {
            foreach (
    $this->_plugins as $plugin)
            {   
                
    $pluginName $plugin->getName();
                
    $output $plugin->handleEvent($eventName$data);
                
    $this->_plugins[$pluginName][$eventName]['output'][] = $output;
            }
        }
      
        
    // ...
      
        
    function attachPlugin($plugin)
        {
            
    $this->_plugins[] = $plugin;
        }
      
      }
      
      
    ?>

  4. #4
    SitePoint Guru
    Join Date
    May 2005
    Location
    Finland
    Posts
    608
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by coo_t2
    I don't know what multiple dispatch is(but I'll read about it) and I thought a lambda was just an anonymous function?
    I'm finding dear Fenrir quite unintelligible as well. Perhaps he's just inventing his own vocabulary.
    I've been rolling around ideas in my head for implementing a plugin
    api in an app that uses a simple little mvc-like framework somewhat similar to mojavi(most of your app code gets executed inside an "Action"). So I was thinking
    each "Action" would trigger certain events and would call the event handler of each plugin that
    has registered with that particular action.
    That would definitely be Observer. I don't know if you saw this thread, but do take a look as I posted a solution of mine there: Creating dynamic plugins for PHP classes

    Visitor is meant for extending the functionality of a set of classes, typically forming a Composite hierarchy, in runtime. A good example - one that our good Doctor loves to throw around a lot - is rendering a tree of components for display. The components themselves needn't know how they should be rendered - you can instead take a Visitor that does know, and have it render the tree. Thus you can get different results by swapping the Visitor instead of touching the code in the components.

    Observer is just that - a way to notify interested parties of changes in an object. These two patterns are really quite different, and although I find Visitor can be quite elusive in its finer points, it still shouldn't by any means get mixed up with Observer.

    I hope this provided some enlightenment.

  5. #5
    SitePoint Addict
    Join Date
    Jan 2005
    Location
    Ireland
    Posts
    349
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Ezku
    I'm finding dear Fenrir quite unintelligible as well. Perhaps he's just inventing his own vocabulary.
    While multiple dispatch is not mumbo jumbo made up by Fernir2, I personally do find his explanation of how it relates to the Visitor pattern (and even more so to PHP) quite ambigious. I could, though, be misunderstanding the concept completely. Could you expand on your description further?

  6. #6
    Non-Member coo_t2's Avatar
    Join Date
    Feb 2003
    Location
    Dog Street
    Posts
    1,819
    Mentioned
    1 Post(s)
    Tagged
    1 Thread(s)
    Quote Originally Posted by Ezku
    I'm finding dear Fenrir quite unintelligible as well. Perhaps he's just inventing his own vocabulary.
    That would definitely be Observer. I don't know if you saw this thread, but do take a look as I posted a solution of mine there: Creating dynamic plugins for PHP classes

    Visitor is meant for extending the functionality of a set of classes, typically forming a Composite hierarchy, in runtime. A good example - one that our good Doctor loves to throw around a lot - is rendering a tree of components for display. The components themselves needn't know how they should be rendered - you can instead take a Visitor that does know, and have it render the tree. Thus you can get different results by swapping the Visitor instead of touching the code in the components.
    So visitors are only really used when a set of classes are interacting with each other in some way, such as the composite example in the article?




    Observer is just that - a way to notify interested parties of changes in an object. These two patterns are really quite different, and although I find Visitor can be quite elusive in its finer points, it still shouldn't by any means get mixed up with Observer.

    I hope this provided some enlightenment.
    It may be the fact that they both use association and callbacks that made me think of them as being
    similar. But I think I better understand the difference now. I think I'll just make a rule that
    I won't consider the visitor anymore until I have a composite to work with.

    Edit:


    Oops, I meant to comment about your plugin classes. They look nice, although I could create a thread entirely dedicated to asking you questions about it.

    Do you care how we use it?

  7. #7
    SitePoint Wizard
    Join Date
    Jan 2005
    Location
    Denmark
    Posts
    1,222
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    The typical visitor is transient. It is typically used to traverse a hierarchy of heterogenous objects, defining operations on the objects within the visitor. After the traversal the visitor is typically discarded. After the traversal there is no longer a relationship between the visitor and the visited objects.

    The observer subscribes to "events" from another instance (or a number of other instances). It's a durable relationship where the "publishers" hold a reference to the "observer" (subscriber). The observer don't define operations as much as "reactions" (i.e. event handlers).
    /mouse

  8. #8
    SitePoint Guru Galo's Avatar
    Join Date
    May 2005
    Location
    Holland!
    Posts
    852
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by coo_t2
    So I've been reading this article ( http://devzone.zend.com/node/view/id/9) and was
    wondering some things about the visitor pattern and also what the precise differences
    are between the observer and the visitor.

    I know there's a difference and I'm pretty sure I understand both patterns(at least the observer, because it's simple).


    But it would be nice to have a sort of "formal" summary of the differences.

    I'll list my thoughts about each and you can tell me what's right and wrong:

    Visitor:
    * is "injected" into an object and can be used as a means of providing the target with an implementation
    * target probably only needs to know one method name of the visitor(visit())
    * internally, visitors are able to use the complete public interface of their targets


    Observer:
    * good for one-to-many relationships between objects
    * has a less intimate relationship with its "target"(the observed)
    * doesn't provide an implementation for the target but just reacts to events



    Do these sound OK? Is there anything you would add or subtract to each?


    A few more questions:

    When you implement a visitor, are you also necessarily implementing a strategy pattern? Since each individual
    visitor could be seen as a "strategy" in and of itself.

    What about plugins(not the Fowler definition)? The visitor seems tailor made for plugins. (and maybe even the observer to a lesser extent)

    Do you have or know of any examples of the visitor pattern that doesn't involve a composite structure?
    without design plans i can't advise you squidelydoo, see, i am not aware of your context, so therefore i am not aware of what problem you like to solve and whether these patterns can help you.

    Be very carefull with patterns, once you know then you will choke in them cause theire oh so oh so handy (at the end youl end up programming producual stuff cause your out of time)

    btw, plug-in = observer, observer::register, observer::dispose, observer::update, and attach an interface please

    class Plugin implements iPlugin{}
    Business as usual is off the menu folks, ...

  9. #9
    SitePoint Guru
    Join Date
    Nov 2002
    Posts
    841
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I think this google tech talk on list describes multiple dispatch (double dispatch) and the visitor pattern.

  10. #10
    SitePoint Guru
    Join Date
    Aug 2005
    Posts
    986
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    That's a good talk, but unfortunately it's about Lisp ((which ((is) really)) scary).

    I'll try to explain double/multiple dispatch, but as always, we should start with something you know already: single dispatch.

    You have two classes, A and B, and they both have a method called foo:

    Code:
    class A
      def foo
        print "foo in A"
      end
    end
    
    class B
      def foo
        print "foo in B"
      end
    end
    Now if we do:

    Code:
    a = new A
    b = new B
    
    a.foo()
    b.foo()
    You'll get:

    Code:
    foo in A
    foo in B
    The computer "knows" that he should execute 'print "foo in A"' if we call a.foo(), and 'print "foo in B"' if we execute b.foo(). That's basic, ok?

    Now we change the syntax a bit:

    Code:
    class A
    class B
    
    def foo(A obj)
      print "foo in A"
    end
    
    def foo(B obj)
      print "foo in B"
    end
    
    a = new A
    b = new B
    
    foo(a)
    foo(b)
    First we define that there are two classes: A and B. Then we defined 2 methods: foo(A obj) and foo(B obj). foo(A obj) means that we are defining a function named foo, which takes a parameter obj of type A. So this function will be called if we pass in an object of class A. Same for B. Now we create an A and a B in the variables A and B. Then we call foo(a) and foo(b). The computer knows that we mean 'print "foo in A"' if we call foo(a) because the class of a is A. Still clear?

    Remember that only the syntax has changed. You may feel different about this code: the method foo(A obj) doesn't belong to class A, does it?

    But what if we use methods with multiple parameters?

    Code:
    class A
    class B
    
    def foo(A obj1, B obj2)
      print "got an A in obj1 and a B in obj 2"
    end
    
    def foo(A obj1, A obj2)
      print "got two A's"
    end
    
    a1 = new A
    a2 = new A
    b1 = new B
    
    foo(a1, b1)
    foo(a1, a2)
    What will this code do? For the first call: foo(a1, b1), your computer will find the corresponding method definition 'print "got an A in obj1 and a B in obj 2"'. The second call: foo(a1, a2) will print "got two A's". Nothing strange about it, the computer just checks two parameters now. What if we call foo(b1, a1)? That will produce a MethodNotDefinedError or something, because there is no corresponding method foo(B obj1, A obj2).

    This is called double dispatch.

    What does this have to do with visitor?

    Let's look at Zend's example:

    Code:
    class Binary extends MyListComponent {
    
        //...
    
        function accept(MyListVisitor $visitor) {
            $visitor->visitBinary($this);
        }
    }
    
    class WebText extends MyListComposite {
    
        //...
    
        function accept(MyListVisitor $visitor) {
            $visitor->visitWebText($this);
            //...
        }
    } 
    
    //...
    
    class SimpleSearchVisitor extends MyListVisitor {
    
       //...
    
        function visitBinary(Binary $comp, $level) {
            // don't match binaries
        }
    
    
        function visitWebText(WebText $comp, $level) {
            if ($this->testText($comp->getTitle()) || $this->testText($comp->getText())) {
                $this->matches[] = $comp;
            }
        }
    }
    What happens here?

    The classes Binary and Note "tell" the visitor which class they have: a Binary calls $visitor->visitBinary(), and a WebText calls visitWebText. They call methods based on their class, they dispatch based on their class. We want that because they way you search is different for different types of objects. You want to search the text of WebTexts, but you don't want to search Binaries.

    Let's translate that to our plain-old-function-language:

    Code:
    class Binary extends MyListComponent
    class WebText extends MyListComponent
    class SimpleSearchVisitor extends MyListVisitor
    
    def accept(Binary binary, MyListVisitor visitor)
      visitbinary(visitor, binary) # the visitor visits the binary
    end
    
    def accept(WebText webtext, MyListVisitor visitor)
      visitwebtext(visitor, webtext)
    end
    
    def visitbinary(SimpleSearchVisitor searcher, Binary comp)
      # don't match binaries
    end
    
    def visitwebtext(SimpleSearchVisitor searcher, WebText comp)
      if(testtext(searcher, gettitle(comp)) || testtext(searcher, gettext(comp)))
        searcher.matches[] = comp
      end
    end
    Not very clear...yet. But it should work: we call visitwebtext if we have a webtext, and we call visitbinary if we have a binary. The accept method looks very similar, we can create a single accept method for both types:

    Code:
    class Binary extends MyListComponent
    class WebText extends MyListComponent
    class SimpleSearchVisitor extends MyListVisitor
    
    def accept(Object node, MyListVisitor visitor)
      visit(visitor, node)
    end
    
    def visit(SimpleSearchVisitor searcher, Binary comp)
      # don't match binaries
    end
    
    def visit(SimpleSearchVisitor searcher, WebText comp)
      if(testtext(searcher, gettitle(comp)) || testtext(searcher, gettext(comp)))
        searcher.matches[] = comp
      end
    end
    Now we have one visit method and one accept method. The visit method takes care of the different types, so accept doesn't have to anymore. The accept method doesn't do much anymore, so we can remove it.

    If we give the methods meaningful names we get this:

    Code:
    class Binary extends MyListComponent
    class WebText extends MyListComponent
    class SimpleSearcher extends MyListSearcher
    
    def searchwith(SimpleSearcher searcher, Binary comp)
      # don't match binaries
    end
    
    def searchwith(SimpleSearcher searcher, WebText comp)
      if(testtext(searcher, gettitle(comp)) || testtext(searcher, gettext(comp)))
        searcher.matches[] = comp
      end
    end
    So we can now do:

    Code:
    searchmethod = new SimpleSearcher("The Search Query")
    thingtosearch = new WebText("The Title", "The Text")
    
    searchwith(searchmethod, thingtosearch) # read: search the WebText with SimpleSearcher
    I think this is much simpler than the visitor pattern: we just define a method which dispatches on the searchmethod: the way we search the thing: SimpleSearch, AdvancedSearch, etc. and the thingtosearch: if we're searching a Binary with SimpleSearch, we don't want to do anything, if we're searching a WebText with SimpleSearch, we want to search the title and the text.

    I hope this makes sense...

  11. #11
    Non-Member
    Join Date
    Jan 2003
    Posts
    5,748
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Umm...

    Not as creditable from my perspective though, sorry. Also, what's with making a posting with Ruby huh? This is the PHP forum after all

  12. #12
    SitePoint Wizard silver trophy kyberfabrikken's Avatar
    Join Date
    Jun 2004
    Location
    Copenhagen, Denmark
    Posts
    6,157
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

  13. #13
    Non-Member coo_t2's Avatar
    Join Date
    Feb 2003
    Location
    Dog Street
    Posts
    1,819
    Mentioned
    1 Post(s)
    Tagged
    1 Thread(s)
    So after reading the c++ example here(there's also one here), my impression is that double/multiple(are they synonymous?) dispatch is mainly just a way to get around methods being
    statically overloaded?

    This is probably much less useful in a dynamically typed language as opposed to a statically typed one, isn't it?(unless you're using PHP5 type hinting, and I'm even sure about that since I'm not using PHP5 yet)

    The problem given in that c++ example just doesn't occur in a dynamically typed language as far as I know.


    Edit:


    On second thought I guess you could equate the need to choose an object at runtime(as with in the visitor/composite article) with the 'statically overloaded method' problem. I guess the two
    problems really are pretty similar.

  14. #14
    SitePoint Guru
    Join Date
    May 2005
    Location
    Finland
    Posts
    608
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Dr Livingston
    Not as creditable from my perspective though, sorry.
    I agree - mine neither. "I think this is much simpler than the visitor pattern" - huh? That is the visitor pattern as far as I can see.
    Also, what's with making a posting with Ruby huh? This is the PHP forum after all
    Well, Ruby syntax slightly modified according to your purposes is absolutely terrific for pseudo, and that's what his example was.

    I do understand that the accept-visitX-construction emulates double dispatch in the way that different handlers are called according to the visited object's type, but I'm not exactly clear on whether or not Fenrir is trying to make a further point here.

  15. #15
    SitePoint Guru
    Join Date
    Aug 2005
    Posts
    986
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I agree - mine neither. "I think this is much simpler than the visitor pattern" - huh? That is the visitor pattern as far as I can see.
    I meant that I find the my last code easier to understand than the first code (Zend's).

    Also, what's with making a posting with Ruby huh? This is the PHP forum after all
    It's not Ruby, I've changed a few things like new A instead of A.new. It is close to Ruby, but it was meant as an easy to read pseudo language.

    I do understand that the accept-visitX-construction emulates double dispatch in the way that different handlers are called according to the visited object's type, but I'm not exactly clear on whether or not Fenrir is trying to make a further point here.
    No, I just find it easier to understand in the double dispatch form, so I thought others might find that as well. It's a higher level view of the concept. If there were any design pattern books for a really low level language, the loop-pattern would be in it:

    Code:
    a = 0
    label :start
    do_something()
    a++
    goto :start if a < 10
    But PHP programmers have a clearer view of this pattern because it is explicit in their language:

    Code:
    for($a = 0; $a < 10; $a++){
       do_something();
    }
    or even:

    Code:
    10.times{ do_something() }
    You forget about the details (goto :start, counter variable $a), and thus it is easier (for most people) to understand the essence of the pattern.

    I thought that the same would apply to visitor/multiple dispatch (apparently not).

    overloading ?
    No, It looks like overloading, but it is different. Overloading is static, and can happen at compile time. Multiple dispatch has to happen at runtime, because you can't tell what an object's class will be.

    The same applies to single dispatch:

    Code:
    class Base {
      function foo() {
        echo "Base";
      }
    }
    
    class A extends Base {
      function foo() {
        echo "A";
      }
    }
    
    class B extends Base {
      function foo() {
        echo "B"; 
      }
    }
    
    Base $o; // type declaration
    
    if($_GET['bar']) {
      $o = new A;
    } else {
      $o = new B;
    }
    
    $o->foo();
    If the polymorphism/overloading happens at compile time, the compiler would see the type declaration Base $o, so it uses the method in Base: echo "Base"; But if if it happens at runtime, the interpreter will just use the method of the class of $o (A or B, not Base).

  16. #16
    SitePoint Wizard REMIYA's Avatar
    Join Date
    May 2005
    Posts
    1,351
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Dr Livingston
    This is the PHP forum after all
    This is exactly the case


Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •