Wiki

root/cobra/trunk/Source/Cobra.Lang/Visitor.cobra

Revision 2045, 3.9 KB (checked in by Chuck.Esterbrook, 3 years ago)

Invoke base.init explicitly.

  • Property svn:eol-style set to native
Line 
1use System.Reflection
2
3
4namespace Cobra.Lang
5
6    class Visitor
7        is abstract
8        """
9        The visitor design pattern is a way of separating an algorithm from an object structure upon
10        which it operates. This enables the addition of new operations to existing object structures
11        without modifying those structures. [1]
12   
13        This class implements the visitor pattern, but via reflection so as to not require that the
14        classes being visited implement any additional methods for "double dispatch". This approach
15        enables less coding and an even greater degree of modularity. It also enables visitation
16        directly on final classes, structs, library classes, etc. with no wrapper classes. [2]
17   
18        In order to leverage this class, you must create a concrete subclass.
19   
20        Subclasses must override .methodName and then simply implement visitation methods with that
21        name and the appropriate parameter types.
22   
23        When enumerating through subobjects, invoke .dispatch to get type specific dispatch. You can
24        also .dispatch on a sequence of objects which will .dispatch on each specific one.
25   
26        If you add a subclass to the class hierarchy that is being visited then you must either
27            (1) remember to implement a method in your visitor class for that specific type, or
28            (2) be content when a visitation method for one of its ancestor classes is invoked for it.
29   
30        If you look at the example much further below, you will get a better idea of what to do.
31        Another read of the notes after examining the example could be useful.
32   
33        Alternatives to the visitor pattern:
34   
35            * Class extensions. You could put multiple, related class extensions in the same file.
36              A pro is that this can make the additional functionality feel like a natural part of the
37              classes. A con is that state must be passed from method to method. Also, method signatures
38              will have to be updated if additional state is added (unless state is grouped into a
39              single context/container object). With the visitor pattern, the state can be stored in the
40              instance of the visitor.
41   
42            * Partial classes. These have the same advantages of class extensions, but without the
43              disadvantage of having to pass state around. However, the con is that this is not
44              available if the classes are external to your project. For example, if the classes come
45              from a library or you are writing a plugin for an application, then partial classes are
46              not available.
47   
48        References:
49   
50            [1] http://en.wikipedia.org/wiki/Visitor_pattern
51            [2] http://www.javaworld.com/javaworld/javatips/jw-javatip98.html
52   
53        Future:
54   
55            * Could add a 'strict' mode where if the argument type is not an exact match for the found
56              method, an exception is raised. This would help when you don't desire that subclasses are
57              silently handled as described above.
58        """
59   
60        var _willCache = true
61        var _methods = Dictionary<of Type, MethodInfo>()
62        var _methodName as String
63       
64        cue init
65            base.init
66            _methodName = .methodName
67            if _methodName[0].isLower
68                _methodName = _methodName[0].toUpper.toString + _methodName[1:]
69   
70        get methodName as String is abstract
71            """
72            Returns the method name looked up in .dispatch.
73            """
74            # ensure result.length > 0
75   
76        def dispatch(obj as Object?)
77            """
78            Performs type specific dispatch on the given object.
79            A subclass can override this method to change the dispatch logic.
80            """
81            if obj is nil, return
82            objType = obj.getType
83            methInfo as MethodInfo?
84            if _willCache, _methods.tryGetValue(objType, out methInfo)
85            if methInfo is nil
86                methInfo = .getType.getMethod(_methodName, @[objType])
87                if methInfo is nil
88                    throw InvalidOperationException('Cannot find a method "[_methodName]" with arg type "[objType]"')
89                _methods[objType] = methInfo to !
90            methInfo.invoke(this, @[obj])  # would be nice to speed this up
91   
92        def dispatch(objects as System.Collections.IEnumerable)
93            """
94            Performs type specific dispatch on each object in order.
95            """
96            for obj in objects, .dispatch(obj)
Note: See TracBrowser for help on using the browser.