⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 #pat5k.htm#

📁 设计模式英文版 作者:Erich Gamma、Richard Helm、Ralph Johnson和John Vlissides 四人帮的书。 学设计模式的必读的书籍!经典中的经典
💻 HTM#
📖 第 1 页 / 共 3 页
字号:
<HTML>

<HEAD><TITLE>Visitor</TITLE></HEAD>

<BODY   BGCOLOR         = #FFFFFF>

<A NAME="top"></A>
<A NAME="Visitor"></A>
<A NAME="intent"></A>
<H2><A HREF="#motivation"><IMG SRC="gifsb/down3.gif" BORDER=0></A> Intent</H2> 

<A NAME="auto1000"></A>
<P>Represent an operation to be performed on the elements of an object
structure.  Visitor lets you define a new operation without changing the
classes of the elements on which it operates.</P>

<A NAME="motivation"></A>
<H2><A HREF="#applicability"><IMG SRC="gifsb/down3.gif" BORDER=0></A> Motivation</H2> 

<A NAME="abssyntree"></A>
<P>Consider a compiler that represents programs as abstract syntax trees.
It will need to perform operations on abstract syntax trees for "static
semantic" analyses like checking that all variables are defined. It
will also need to generate code. So it might define operations for
type-checking, code optimization, flow analysis, checking for variables
being assigned values before they're used, and so on. Moreover, we could
use the abstract syntax trees for pretty-printing, program
restructuring, code instrumentation, and computing various metrics of a
program.</P>

<A NAME="auto1001"></A>
<P>Most of these operations will need to treat nodes that represent
assignment statements differently from nodes that represent variables or
arithmetic expressions. Hence there will be one class for assignment
statements, another for variable accesses, another for arithmetic
expressions, and so on. The set of node classes depends on the language
being compiled, of course, but it doesn't change much for a given
language.</P>

<A NAME="abssync"></A>
<P ALIGN=CENTER><IMG SRC="Pictures/visit006.gif"></P>

<A NAME="auto1002"></A>
<P>This diagram shows part of the Node class hierarchy.  The problem here
is that distributing all these operations across the various node
classes leads to a system that's hard to understand, maintain, and
change. It will be confusing to have type-checking code mixed with
pretty-printing code or flow analysis code. Moreover, adding a new
operation usually requires recompiling all of these classes. It would be
better if each new operation could be added separately, and the node
classes were independent of the operations that apply to them.</P>

<A NAME="def-visitor"></A>
<P>We can have both by packaging related operations from each class in a
separate object, called a <STRONG>visitor</STRONG>, and passing it to
elements of the abstract syntax tree as it's traversed. When an element
"accepts" the visitor, it sends a request to the visitor that encodes
the element's class. It also includes the element as an argument. The
visitor will then execute the operation for that element&#151;the
operation that used to be in the class of the element.</P>

<A NAME="typecheck"></A>
<P>For example, a compiler that didn't use visitors might type-check a
procedure by calling the TypeCheck operation on its abstract syntax
tree. Each of the nodes would implement TypeCheck by calling TypeCheck
on its components (see the preceding class diagram). If the compiler
type-checked a procedure using visitors, then it would create a
TypeCheckingVisitor object and call the Accept operation on the
abstract syntax tree with that object as an argument. Each of the
nodes would implement Accept by calling back on the visitor: an
assignment node calls VisitAssignment operation on the visitor, while
a variable reference calls VisitVariableReference. What used to be the
TypeCheck operation in class AssignmentNode is now the VisitAssignment
operation on TypeCheckingVisitor.</P>

<A NAME="auto1003"></A>
<P>To make visitors work for more than just type-checking, we need an
abstract parent class NodeVisitor for all visitors of an abstract syntax
tree. NodeVisitor must declare an operation for each node class. An
application that needs to compute program metrics will define new
subclasses of NodeVisitor and will no longer need to add
application-specific code to the node classes. The Visitor pattern
encapsulates the operations for each compilation phase in a Visitor
associated with that phase.</P>

<A NAME="332c"></A>
<P ALIGN=CENTER><IMG SRC="Pictures/visit113.gif"></P>

<A NAME="333c"></A>
<P ALIGN=CENTER><IMG SRC="Pictures/visit112.gif"></P>

<A NAME="auto1004"></A>
<P>With the Visitor pattern, you define two class hierarchies: one for the
elements being operated on (the Node hierarchy) and one for the visitors
that define operations on the elements (the NodeVisitor hierarchy). You
create a new operation by adding a new subclass to the visitor class
hierarchy. As long as the grammar that the compiler accepts doesn't
change (that is, we don't have to add new Node subclasses), we can add
new functionality simply by defining new NodeVisitor subclasses.</P>

<A NAME="applicability"></A>
<H2><A HREF="#structure"><IMG SRC="gifsb/down3.gif" BORDER=0></A> Applicability</H2> 

<A NAME="auto1005"></A>
<P>Use the Visitor pattern when</P>

<UL>

<A NAME="auto1006"></A>
<LI>an object structure contains many classes of objects with differing
interfaces, and you want to perform operations on these objects that
depend on their concrete classes.</LI>
<A NAME="auto1007"></A>
<P></P>
<A NAME="auto1008"></A>
<LI>many distinct and unrelated operations need to be performed on objects
in an object structure, and you want to avoid "polluting" their
classes with these operations. Visitor lets you keep related operations
together by defining them in one class. When the object structure is
shared by many applications, use Visitor to put operations in just those
applications that need them.</LI>
<A NAME="auto1009"></A>
<P></P>
<A NAME="auto1010"></A>
<LI>the classes defining the object structure rarely change, but you often
want to define new operations over the structure. Changing the object
structure classes requires redefining the interface to all visitors,
which is potentially costly. If the object structure classes change
often, then it's probably better to define the operations in those
classes.</LI>

</UL>

<A NAME="structure"></A>
<H2><A HREF="#participants"><IMG SRC="gifsb/down3.gif" BORDER=0></A>
Structure</H2> 

<P ALIGN=CENTER><IMG SRC="Pictures/visitor.gif"></P>

<A NAME="participants"></A>
<H2><A HREF="#collaborations"><IMG SRC="gifsb/down3.gif" BORDER=0></A>
Participants</H2>

<UL>

<A NAME="auto1011"></A>
<LI><B>Visitor</B> (NodeVisitor)</LI>

<A NAME="auto1012"></A>
<P></P>

    <UL>

    <A NAME="auto1013"></A>
<LI>declares a Visit operation for each class of ConcreteElement
    in the object structure.  The operation's name and
    signature identifies the class that sends the Visit
    request to the visitor. That lets the visitor determine the
    concrete class of the element being visited.  Then the visitor
    can access the element directly through its particular interface.</LI>

    </UL>

<A NAME="auto1014"></A>
<P></P>

<A NAME="auto1015"></A>
<LI><B>ConcreteVisitor</B> (TypeCheckingVisitor)</LI>

<A NAME="auto1016"></A>
<P></P>

    <UL>

    <A NAME="auto1017"></A>
<LI>implements each operation declared by Visitor. Each operation
    implements a fragment of the algorithm defined for the corresponding
    class of object in the structure.  ConcreteVisitor provides the
    context for the algorithm and stores its local state. This state often
    accumulates results during the traversal of the structure.</LI>

    </UL>

<A NAME="auto1018"></A>
<P></P>

<A NAME="part-element"></A>
<LI><B>Element</B> (Node)</LI>

<A NAME="auto1019"></A>
<P></P>

    <UL>

    <A NAME="auto1020"></A>
<LI>defines an Accept operation that takes a visitor as an argument.</LI>

    </UL>

<A NAME="auto1021"></A>
<P></P>

<A NAME="auto1022"></A>
<LI><B>ConcreteElement</B> (AssignmentNode,VariableRefNode)</LI>

<A NAME="auto1023"></A>
<P></P>

    <UL>

    <A NAME="auto1024"></A>
<LI>implements an Accept operation that takes a visitor as an
    argument.</LI>

    </UL>

<A NAME="auto1025"></A>
<P></P>

<A NAME="auto1026"></A>
<LI><B>ObjectStructure</B> (Program)</LI>

<A NAME="auto1027"></A>
<P></P>

    <UL>

    <A NAME="auto1028"></A>
<LI>can enumerate its elements.</LI>

    <A NAME="auto1029"></A>
<P><!-- extra space --></P>

    <A NAME="auto1030"></A>
<LI>may provide a high-level interface to allow the visitor
    to visit its elements.</LI>

    <A NAME="auto1031"></A>
<P><!-- extra space --></P>

    <A NAME="auto1032"></A>
<LI>may either be a composite (see
    <A HREF="pat4cfs.htm" TARGET="_mainDisplayFrame">Composite&nbsp;(163)</A>)
    or a collection such as a list or a set.</LI>

    </UL>

</UL>

<A NAME="collaborations"></A>
<H2><A HREF="#consequences"><IMG SRC="gifsb/down3.gif" BORDER=0></A> Collaborations</H2>

<UL>

<A NAME="auto1033"></A>
<LI>A client that uses the Visitor pattern must create a ConcreteVisitor
object and then traverse the object structure, visiting each element
with the visitor.</LI>
<A NAME="auto1034"></A>
<P></P>
<A NAME="auto1035"></A>
<LI>When an element is visited, it calls the Visitor operation that
corresponds to its class.  The element supplies itself as an argument
to this operation to let the visitor access its state, if necessary.

<A NAME="auto1036"></A>
<P>The following interaction diagram illustrates the collaborations
between an object structure, a visitor, and two elements:</P>

<P ALIGN=CENTER><IMG SRC="Pictures/visit003.gif"></P>

</LI>

</UL>

<A NAME="consequences"></A>
<H2><A HREF="#implementation"><IMG SRC="gifsb/down3.gif" BORDER=0></A> Consequences</H2> 

<A NAME="auto1037"></A>
<P>Some of the benefits and liabilities of the Visitor pattern are as follows:</P>

<OL>

<A NAME="auto1038"></A>
<LI><EM>Visitor makes adding new operations easy.</EM>
Visitors make it easy to add operations that depend on the components of
complex objects. You can define a new operation over an object structure
simply by adding a new visitor. In contrast, if you spread functionality
over many classes, then you must change each class to define a new
operation.</LI>
<A NAME="auto1039"></A>
<P></P>
<A NAME="auto1040"></A>
<LI><EM>A visitor gathers related operations and separates unrelated ones.</EM>
Related behavior isn't spread over the classes defining the object
structure; it's localized in a visitor. Unrelated sets of behavior are
partitioned in their own visitor subclasses. That simplifies both the
classes defining the elements and the algorithms defined in the
visitors. Any algorithm-specific data structures can be hidden in the
visitor.</LI>
<A NAME="auto1041"></A>
<P></P>
<A NAME="auto1042"></A>
<LI><EM>Adding new ConcreteElement classes is hard.</EM>
The Visitor pattern makes it hard to add new subclasses of Element. Each
new ConcreteElement gives rise to a new abstract operation on Visitor and
a corresponding implementation in every ConcreteVisitor class. Sometimes a
default implementation can be provided in Visitor that can be inherited
by most of the ConcreteVisitors, but this is the exception rather than
the rule.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -