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

📄 pat3b.htm

📁 设计模式英文版 作者:Erich Gamma、Richard Helm、Ralph Johnson和John Vlissides 四人帮的书。 学设计模式的必读的书籍!经典中的经典
💻 HTM
📖 第 1 页 / 共 2 页
字号:
    class MazeBuilder {
    public:
        virtual void BuildMaze() { }
        virtual void BuildRoom(int room) { }
        virtual void BuildDoor(int roomFrom, int roomTo) { }
    
        virtual Maze* GetMaze() { return 0; }
    protected:
        MazeBuilder();
    };
</PRE>

<A NAME="auto1053"></A>
<P>This interface can create three things: (1) the maze, (2) rooms with a
particular room number, and (3) doors between numbered rooms.  The
<CODE>GetMaze</CODE> operation returns the maze to the client.
Subclasses of <CODE>MazeBuilder</CODE> will override this operation to
return the maze that they build.</P>

<A NAME="auto1054"></A>
<P>All the maze-building operations of <CODE>MazeBuilder</CODE> do nothing
by default. They're not declared pure virtual to let derived classes
override only those methods in which they're interested.</P>

<A NAME="auto1055"></A>
<P>Given the <CODE>MazeBuilder</CODE> interface, we can change the
<CODE>CreateMaze</CODE> member function to take this builder as a
parameter.</P>

<A NAME="auto1056"></A>
<PRE>
    Maze* MazeGame::CreateMaze (MazeBuilder&amp; builder) {
        builder.BuildMaze();
    
        builder.BuildRoom(1);
        builder.BuildRoom(2);
        builder.BuildDoor(1, 2);
    
        return builder.GetMaze();
    }
</PRE>

<A NAME="auto1057"></A>
<P>Compare this version of <CODE>CreateMaze</CODE> with the original.
Notice how the builder hides the internal representation of the
Maze&#151;that is, the classes that define rooms, doors, and walls&#151;and
how these parts are assembled to complete the final maze.  Someone
might guess that there are classes for representing rooms and doors,
but there is no hint of one for walls.  This makes it easier to change
the way a maze is represented, since none of the clients of
<CODE>MazeBuilder</CODE> has to be changed.</P>

<A NAME="auto1058"></A>
<P>Like the other creational patterns, the Builder pattern encapsulates
how objects get created, in this case through the interface defined by
<CODE>MazeBuilder</CODE>.  That means we can reuse <CODE>MazeBuilder</CODE>
to build different kinds of mazes.  The <CODE>CreateComplexMaze</CODE>
operation gives an example:</P>

<A NAME="auto1059"></A>
<PRE>
    Maze* MazeGame::CreateComplexMaze (MazeBuilder&amp; builder) {
        builder.BuildRoom(1);
        // ...
        builder.BuildRoom(1001);
    
        return builder.GetMaze();
    }
</PRE>

<A NAME="auto1060"></A>
<P>Note that <CODE>MazeBuilder</CODE> does not create mazes itself; its
main purpose is just to define an interface for creating mazes.  It
defines empty implementations primarily for convenience.  Subclasses of
<CODE>MazeBuilder</CODE> do the actual work.</P>

<A NAME="standardmazebuilder"></A>
<P>The subclass <CODE>StandardMazeBuilder</CODE> is an implementation that
builds simple mazes. It keeps track of the maze it's building in the
variable <CODE>_currentMaze</CODE>.</P>

<A NAME="auto1061"></A>
<PRE>
    class StandardMazeBuilder : public MazeBuilder {
    public:
        StandardMazeBuilder();
    
        virtual void BuildMaze();
        virtual void BuildRoom(int);
        virtual void BuildDoor(int, int);
    
        virtual Maze* GetMaze();
    private:
        Direction CommonWall(Room*, Room*);
        Maze* _currentMaze;
    };
</PRE>

<A NAME="auto1062"></A>
<P><CODE>CommonWall</CODE> is a utility operation that determines
the direction of the common wall between two rooms.</P>

<A NAME="auto1063"></A>
<P>The <CODE>StandardMazeBuilder</CODE> constructor simply initializes
<CODE>_currentMaze</CODE>.</P>

<A NAME="auto1064"></A>
<PRE>
    StandardMazeBuilder::StandardMazeBuilder () {
        _currentMaze = 0;
    }
</PRE>

<A NAME="auto1065"></A>
<P><CODE>BuildMaze</CODE> instantiates a <CODE>Maze</CODE> that
other operations will assemble and eventually return to the client
(with <CODE>GetMaze</CODE>).</P>

<A NAME="auto1066"></A>
<PRE>
    void StandardMazeBuilder::BuildMaze () {
        _currentMaze = new Maze;
    }
    
    Maze* StandardMazeBuilder::GetMaze () {
        return _currentMaze;
    }
</PRE>

<A NAME="auto1067"></A>
<P>The <CODE>BuildRoom</CODE> operation creates a room and builds the
walls around it:</P>

<A NAME="auto1068"></A>
<PRE>
    void StandardMazeBuilder::BuildRoom (int n) {
        if (!_currentMaze->RoomNo(n)) {
            Room* room = new Room(n);
            _currentMaze->AddRoom(room);
    
            room->SetSide(North, new Wall);
            room->SetSide(South, new Wall);
            room->SetSide(East, new Wall);
            room->SetSide(West, new Wall);
        }
    }
</PRE>

<A NAME="auto1069"></A>
<P>To build a door between two rooms, <CODE>StandardMazeBuilder</CODE> looks
up both rooms in the maze and finds their adjoining wall:</P>

<A NAME="auto1070"></A>
<PRE>
    void StandardMazeBuilder::BuildDoor (int n1, int n2) {
        Room* r1 = _currentMaze->RoomNo(n1);
        Room* r2 = _currentMaze->RoomNo(n2);
        Door* d = new Door(r1, r2);
    
        r1->SetSide(CommonWall(r1,r2), d);
        r2->SetSide(CommonWall(r2,r1), d);
    }
</PRE>

<A NAME="auto1071"></A>
<P>Clients can now use <CODE>CreateMaze</CODE> in conjunction with
<CODE>StandardMazeBuilder</CODE> to create a maze:</P>

<A NAME="auto1072"></A>
<PRE>
    Maze* maze;
    MazeGame game;
    StandardMazeBuilder builder;
    
    game.CreateMaze(builder);
    maze = builder.GetMaze();
</PRE>

<A NAME="auto1073"></A>
<P>We could have put all the <CODE>StandardMazeBuilder</CODE> operations in
<CODE>Maze</CODE> and let each <CODE>Maze</CODE> build itself.  But making
<CODE>Maze</CODE> smaller makes it easier to understand and modify, and
<CODE>StandardMazeBuilder</CODE> is easy to separate from <CODE>Maze</CODE>.
Most importantly, separating the two lets you have a variety of
<CODE>MazeBuilders</CODE>, each using different classes for rooms, walls,
and doors.</P>

<A NAME="auto1074"></A>
<P>A more exotic <CODE>MazeBuilder</CODE> is
<CODE>CountingMazeBuilder</CODE>.  This builder doesn't create a
maze at all; it just counts the different kinds of components that
would have been created.</P>

<A NAME="auto1075"></A>
<PRE>
    class CountingMazeBuilder : public MazeBuilder {
    public:
        CountingMazeBuilder();
    
        virtual void BuildMaze();
        virtual void BuildRoom(int);
        virtual void BuildDoor(int, int);
        virtual void AddWall(int, Direction);
    
        void GetCounts(int&amp;, int&amp;) const;
    private:
        int _doors;
        int _rooms;
    };
</PRE>

<A NAME="auto1076"></A>
<P>The constructor initializes the counters, and the overridden
<CODE>MazeBuilder</CODE> operations increment them accordingly.</P>

<A NAME="auto1077"></A>
<PRE>
    CountingMazeBuilder::CountingMazeBuilder () {
        _rooms = _doors = 0;
    }
    
    void CountingMazeBuilder::BuildRoom (int) {
        _rooms++;
    }
    
    void CountingMazeBuilder::BuildDoor (int, int) {
        _doors++;
    }
    
    void CountingMazeBuilder::GetCounts (
        int&amp; rooms, int&amp; doors
    ) const {
        rooms = _rooms;
        doors = _doors;
    }
</PRE>

<A NAME="auto1078"></A>
<P>Here's how a client might use a <CODE>CountingMazeBuilder</CODE>:</P>

<A NAME="auto1079"></A>
<PRE>
    int rooms, doors;
    MazeGame game;
    CountingMazeBuilder builder;
    
    game.CreateMaze(builder);
    builder.GetCounts(rooms, doors);
    
    cout << "The maze has "
         << rooms << " rooms and "
         << doors << " doors" << endl;
</PRE>

<A NAME="knownuses"><A>
<H2><A HREF="#relatedpatterns"><IMG SRC="gifsb/down3.gif" BORDER=0></A> Known Uses</H2>

<A NAME="auto1080"></A>
<P>The RTF converter application is from ET++&nbsp;[<A HREF="vfs.htm?doc=bib-0.htm&fid=bb&hid=et++" TARGET="_mainDisplayFrame">WGM88</A>].  Its text building block uses a
builder to process text stored in the RTF format.</P>

<A NAME="et-use-builder"></A>
<A NAME="smalltalk-use-builder"></A>
<P>Builder is a common pattern in
Smalltalk-80&nbsp;[<A HREF="vfs.htm?doc=bib-0.htm&fid=bb&hid=parcplace_smalltalk" TARGET="_mainDisplayFrame">Par90</A>]:</P>

<UL>

<A NAME="auto1081"></A>
<LI>The Parser class in the compiler subsystem is a Director that takes a
ProgramNodeBuilder object as an argument.  A Parser object notifies
its ProgramNodeBuilder object each time it recognizes a syntactic
construct.  When the parser is done, it asks the builder for the parse
tree it built and returns it to the client.</LI>
<A NAME="auto1082"></A>
<P></P>
<A NAME="auto1083"></A>
<LI>ClassBuilder is a builder that Classes use to create subclasses for
themselves.  In this case a Class is both the Director and the
Product.</LI>
<A NAME="auto1084"></A>
<P></P>
<A NAME="auto1085"></A>
<LI>ByteCodeStream is a builder that creates a compiled method as a byte
array.  ByteCodeStream is a nonstandard use of the Builder pattern,
because the complex object it builds is encoded as a byte array, not
as a normal Smalltalk object.  But the interface to ByteCodeStream is
typical of a builder, and it would be easy to replace ByteCodeStream
with a different class that represented programs as a composite
object.</LI>

</UL>

<A NAME="auto1086"></A>
<P>The Service Configurator framework from the Adaptive Communications
Environment uses a builder to construct network service components
that are linked into a server at run-time&nbsp;[<A HREF="vfs.htm?doc=bib-0.htm&fid=bb&hid=schmidt94" TARGET="_mainDisplayFrame">SS94</A>].  The components are described
with a configuration language that's parsed by an LALR(1) parser.
The semantic actions of the parser perform operations on the builder
that add information to the service component.  In this case, the
parser is the Director.</P>

<A NAME="relatedpatterns"></A>
<H2><A HREF="#last"><IMG SRC="gifsb/down3.gif" BORDER=0></A> Related Patterns</H2> 

<A NAME="auto1087"></A>
<P><A HREF="pat3afs.htm" TARGET="_mainDisplayFrame">Abstract Factory&nbsp;(87)</A> is
similar to Builder in that it too may construct complex objects.
The primary difference is that the Builder pattern focuses on
constructing a complex object step by step.  Abstract Factory's
emphasis is on families of product objects (either simple or
complex).  Builder returns the product as a final step, but as far
as the Abstract Factory pattern is concerned, the product gets
returned immediately.</P>

<A NAME="auto1088"></A>
<P>A <A HREF="pat4cfs.htm" TARGET="_mainDisplayFrame">Composite&nbsp;(163)</A> is what the
builder often builds.</P>

<A NAME="last"></A>
<P><A HREF="#intent"><IMG SRC="gifsb/up3.gif" BORDER=0></A><BR>
<A HREF="pat3cfs.htm" TARGET="_mainDisplayFrame"><IMG SRC="gifsb/rightar3.gif"
	ALIGN=TOP BORDER=0></A> <A HREF="pat3cfs.htm"
	TARGET="_mainDisplayFrame">Factory Method</A><BR>
<A HREF="pat3afs.htm" TARGET="_mainDisplayFrame"><IMG SRC="gifsb/leftarr3.gif"
	ALIGN=TOP BORDER=0></A> <A HREF="pat3afs.htm"
	TARGET="_mainDisplayFrame">Abstract Factory</A>
</P>

</BODY>

</HTML>

⌨️ 快捷键说明

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