Visitor mode
origin
The Visitor mode in Delphi has expanded in the basic Visitor mode. For more information on Visitor mode, please refer to [Gam , Pages 331..344].
purpose
Indicates an operation of neutralizing elements that acts on a target structure. It allows you to define new operations for these elements without changing the class of each element.
[GAM , Page 331].
motivation
Consider an object-oriented modeling tool, such as 'Rational Rose, ModelMaker', which represents a model as a member of the class and class.
A number of operating membership functions are provided on the modeling tool, such as all members of the list class, generated class code frame, reverse engineering, etc.
Most of these operations do different operations for different members. It divides the member into a field (Methods),
Properties. Because we must establish a class specifically handled fields, dedicated to the class of Methods, and the like. The collection of members classes is of course dependent on the compiled language. But there is no change in a given language.
A framework of some member classes is shown as shown. The problem is generated, if I divide all these operations to different member classes,
It will cause the entire system to be difficult to understand, modify, and maintain. Put the class code generation with the class member will be confusing. Some classes that should be recompiled when adding new operations (at least all related systems). There is a way: you may independently add a new action and this member class is independent of the operation acting on it.
To achieve the above two goals, we can pack each class in an independent object (called Visitor)
And passed this object to the current member when traversing a list of members. When a member 'accepts' access, the member sends a request to the visitor containing its own information. The member is requested from itself as a parameter. Visitors perform these operations.
For example: A code generator that does not use the visitor may pass abstract ways of the member class: Tmember.WriteInterfaceCode (Output: TStream) generates code. Each member calls WriteInterfaceCode to generate an appropriate output code. If you generate a code by visitor, a TinterfaceCodeVisitor object is created and the parameter is called on the member list as an Acceptvisitor method to access the object. Each member will call the Visitor: A field will call the visitor's Visitfield method, and a method calls the VisitMethod method. This way, the previous class TField's WriteInterfaceCode operation is now a Visitfield operation for TinterfaceCodevisitor.
In order to make the visitor not only only code generation, we need the visitors of all the members lists with an abstract parent class Tmembervisitor. Tmembervisitor must define a method for each member. A application that needs to output members to HTML format will define new subclasses of Tmembervisitor and no longer need to increase the code associated with specific applications in the member class. Visitor mode Pack each operation in a related Visitor
Using Visitor mode, you must define two levels: a one of the elements that should be accepted (TMEMBER Hierarchy) The other is defined to the elements (TMEMBERVISITOR Hierarchy). Add a new subclass when adding a new operation. I may simply define a new Tmembervisitor subclass to add new features.
application
The following code demonstrates the application of the Visitor mode of the class Tmember described above
Type
Tmember = Class (TOBJECT)
public
Procedure Acceptmembervisitor (Visitor: Tmembervisitor); Virtual; End;
Tfield = Class (TMEMBER)
public
Procedure Acceptmembervisitor (Visitor: Tmembervisitor); OVERRIDE;
END;
TMETHOD = Class (TMEMBER)
public
Procedure Acceptmembervisitor (Visitor: Tmembervisitor); OVERRIDE;
END;
TPROPERTY = Class (TMEMBER)
public
Procedure Acceptmembervisitor (Visitor: Tmembervisitor); OVERRIDE;
END;
Tmembervisitor = Class (TOBJECT)
public
Procedure Visitfield (Instance: Tfield); Virtual;
Procedure Visitmember (Instance: Tmember); Virtual;
Procedure Visitmeth (Instance: TMethod); Virtual;
Procedure VisitProperty (Instance: tproperty); virtual;
END;
IMPLEMENTATION
{Tmember}
Begin
Visitor.Visitmember (Self);
END;
{Tfield}
Procedure Tfield.Acceptmembervisitor (Visitor: Tmembervisitor);
Begin
END;
{TMETHOD}
Procedure Tmethod.AcceptMembervisitor (Visitor: Tmembervisitor);
Begin
Visitor.visitmethod (Self);
END;
{Tproperty}
Procedure tproperty.acceptmembervisitor (Visitor: Tmembervisitor);
Begin
Visitor.visitProperty (Self);
END;
{Tmembervisitor}
Procedure Tmembervisitor.visitfield (Instance: Tfield);
Begin
END;
Procedure Tmembervisitor.Visitmember (Instance: Tmember);
Begin
END;
Procedure Tmembervisitor.Visitmethod (Instance: TMethod);
Begin
END;
Procedure Tmembervisitor.visitProperty (Instance: tproperty);
Begin
END;
Description:
· Tmember, Tfield, TMethod and TProperty implement an Acceptmembervisitor method. These methods are embedded in the mode.
· The Tmembervisitor class implements a method such as Visitmember, Visitfield, etc. Tmembervisitor is an abstract class whose approach is achieved by specific subclasses.
Below is an implementation of a simple code generator.
Code introduction:
• TcodeGenerationVisitor is a visitor for code generator for implementing members.
· Visitors define a context-related properties: Output: TtextStream,
· It must be determined before the Visitxxx call, such as: DrawingVisitor typically requires a context including Canvas to support draw operations. The context gives a code generator before traversing the entire Member. · Code generator will complete all code of the generated class
To really understand the Visitor mode, you can perform this example and further learn the double dispatcher: Accept / Visit.
UNIT CODEGENERATORS;
Interface
Uses Classes, TextStreams;
Type
TcodeGenerator = Class (TOBJECT)
public
Procedure generate (MEMBERS: TLIST; OUTPUT: TTEXTSTREAM);
END;
IMPLEMENTATION
Uses members;
Type
TcodeGenerationVisitor = Class (Tmembervisitor)
Private
Foutput: TTEXTSTREAM;
public
Procedure: Tfield; Override;
Procedure Visitmethod (Instance: TMethod); OVERRIDE;
Procedure Visitproperty (Instance: tproperty); OVERRIDE;
Property Output: TtextStream Read Foutput Write Foutput;
END;
{TcodeGenerationVisitor}
Procedure TcodeGenerationVisitor.visitfield (Instance: tfield);
Begin
Output.writelnfmt ('% s:% s;', [instance.name, instance.dataname]);
END;
Procedure TcodeGenerationVisitor.Visitmethod (Instance: TMethod);
VAR
MKSTR, DTSTR: STRING;
Begin
Case Instance.Methodkind of
MKConstructor: mkstr: = 'constructor';
MKDESTRUCTOR: MKSTR: = 'DESTRUCTOR';
MkProcedure: MKSTR: = 'procadure';
MKFUNTION: MKSTR: = 'Function';
END;
IF instance.methodkind = mkfunction then
DTSTR: = ':' instance.dataname
Else
DTSTR: = '';
The {code is incomplete, it is now sufficient to demonstrate the TMETHOD code generation}
Output.writelnfmt ('% s% s% s% s;'
[MKSTR, Instance.Name, Instance.Parameters, DTSTR]);
END;
Procedure TcodeGenerationVisitor.visitProperty (Instance: tproperty);
Begin
Output.writelnfmt ('Property% S:% s ied% s write% s; "
Instance.Name, Instance.Dataname,
Instance.readspecifier, instance.writespecifier]);
End; {tcodegenerator}
Procedure tcodegenerator.generate (MEMBERS: TLIST; OUTPUT: TTEXTSTREAM);
VAR
I: integer;
Begin
{Write class definition}
Output.writeLine ('Tsample = Class (TOBJECT)');
{it is good! Add to code generator Accessor}
Visitor: = tcodegenerationvisitor.create;
Try
{Remember to provide context for access to better access the Visitxxx method. }
For i: = 0 to Members.count - 1 DO
{Code specific segment, good things happen}
Tmember (MEMBERS [I]). Acceptmembervisitor (Visitor);
Finally
Visitor.free;
END;
The code generation of the {class member is completed.
Output.writeLine ('end;');
END;
Delphi instance
Be organized
// A lot from "design mode",