📄 pat4c-1.htm
字号:
children, including linked lists, trees, arrays, and hash tables. The
choice of data structure depends (as always) on efficiency. In fact,
it isn't even necessary to use a general-purpose data structure at
all. Sometimes composites have a variable for each child, although this
requires each subclass of Composite to implement its own management
interface. See <A HREF="pat5cfs-1.htm" tppabs="http://ultra/development/DesignPatterns/lowres/pat5cfs.htm" TARGET="_mainDisplayFrame">Interpreter (243)</A> for an example.</LI>
</OL>
<A NAME="samplecode"></A>
<H2><A HREF="#knownuses"><IMG SRC="down3-1.gif" tppabs="http://ultra/development/DesignPatterns/lowres/gifsb/down3.gif" BORDER=0 ALT="next:
Known Uses"></A> Sample Code</H2>
<A NAME="auto1082"></A>
<P>Equipment such as computers and stereo components are often organized
into part-whole or containment hierarchies. For example, a chassis can
contain drives and planar boards, a bus can contain cards, and a
cabinet can contain chassis, buses, and so forth. Such structures can
be modeled naturally with the Composite pattern.</P>
<A NAME="auto1083"></A>
<P><CODE>Equipment</CODE> class defines an interface for all equipment in
the part-whole hierarchy.</P>
<A NAME="auto1084"></A>
<PRE>
class Equipment {
public:
virtual ~Equipment();
const char* Name() { return _name; }
virtual Watt Power();
virtual Currency NetPrice();
virtual Currency DiscountPrice();
virtual void Add(Equipment*);
virtual void Remove(Equipment*);
virtual Iterator<Equipment*>* CreateIterator();
protected:
Equipment(const char*);
private:
const char* _name;
};
</PRE>
<A NAME="auto1085"></A>
<P><CODE>Equipment</CODE> declares operations that return the
attributes of a piece of equipment, like its power consumption and
cost. Subclasses implement these operations for specific kinds of
equipment. <CODE>Equipment</CODE> also declares a
<CODE>CreateIterator</CODE> operation that returns an <CODE>Iterator</CODE>
(see <A HREF="chapCfs-1.htm" tppabs="http://ultra/development/DesignPatterns/lowres/chapCfs.htm" TARGET="_mainDisplayFrame">Appendix C</A>)
for accessing its parts. The
default implementation for this operation returns a NullIterator,
which iterates over the empty set.</P>
<A NAME="auto1086"></A>
<P>Subclasses of <CODE>Equipment</CODE> might include Leaf classes that
represent disk drives, integrated circuits, and switches:</P>
<A NAME="auto1087"></A>
<PRE>
class FloppyDisk : public Equipment {
public:
FloppyDisk(const char*);
virtual ~FloppyDisk();
virtual Watt Power();
virtual Currency NetPrice();
virtual Currency DiscountPrice();
};
</PRE>
<A NAME="auto1088"></A>
<P><CODE>CompositeEquipment</CODE> is the base class for equipment
that contains other equipment. It's also a subclass of
<CODE>Equipment</CODE>.</P>
<A NAME="auto1089"></A>
<PRE>
class CompositeEquipment : public Equipment {
public:
virtual ~CompositeEquipment();
virtual Watt Power();
virtual Currency NetPrice();
virtual Currency DiscountPrice();
virtual void Add(Equipment*);
virtual void Remove(Equipment*);
virtual Iterator<Equipment*>* CreateIterator();
protected:
CompositeEquipment(const char*);
private:
List<Equipment*> _equipment;
};
</PRE>
<A NAME="auto1090"></A>
<P><CODE>CompositeEquipment</CODE> defines the operations for accessing and
managing subequipment. The operations <CODE>Add</CODE> and
<CODE>Remove</CODE> insert and delete equipment from the list of equipment
stored in the <CODE>_equipment</CODE> member. The operation
<CODE>CreateIterator</CODE> returns an iterator (specifically, an
instance of <CODE>ListIterator</CODE>) that will traverse this list.</P>
<A NAME="auto1091"></A>
<P>A default implementation of <CODE>NetPrice</CODE> might use
<CODE>CreateIterator</CODE> to sum the net prices of the
subequipment<SUP><A NAME="fn2"></A><A HREF="#footnote2">2</A></SUP>:</P>
<A NAME="auto1092"></A>
<PRE>
Currency CompositeEquipment::NetPrice () {
Iterator<Equipment*>* i = CreateIterator();
Currency total = 0;
for (i->First(); !i->IsDone(); i->Next()) {
total += i->CurrentItem()->NetPrice();
}
delete i;
return total;
}
</PRE>
<A NAME="auto1093"></A>
<P>Now we can represent a computer chassis as a subclass of
<CODE>CompositeEquipment</CODE> called <CODE>Chassis</CODE>.
<CODE>Chassis</CODE> inherits the child-related operations from
<CODE>CompositeEquipment</CODE>.</P>
<A NAME="auto1094"></A>
<PRE>
class Chassis : public CompositeEquipment {
public:
Chassis(const char*);
virtual ~Chassis();
virtual Watt Power();
virtual Currency NetPrice();
virtual Currency DiscountPrice();
};
</PRE>
<A NAME="auto1095"></A>
<P>We can define other equipment containers such as
<CODE>Cabinet</CODE> and <CODE>Bus</CODE> in a similar way.
That gives us everything we need to assemble equipment into a (pretty
simple) personal computer:</P>
<A NAME="auto1096"></A>
<PRE>
Cabinet* cabinet = new Cabinet("PC Cabinet");
Chassis* chassis = new Chassis("PC Chassis");
cabinet->Add(chassis);
Bus* bus = new Bus("MCA Bus");
bus->Add(new Card("16Mbs Token Ring"));
chassis->Add(bus);
chassis->Add(new FloppyDisk("3.5in Floppy"));
cout << "The net price is " << chassis->NetPrice() << endl;
</PRE>
<A NAME="knownuses"></A>
<H2><A HREF="#relatedpatterns"><IMG SRC="down3-1.gif" tppabs="http://ultra/development/DesignPatterns/lowres/gifsb/down3.gif" BORDER=0
ALT="next: Related Patterns"></A> Known Uses</H2>
<A NAME="auto1097"></A>
<P>Examples of the Composite pattern can be found in almost all
object-oriented systems. The original View class of Smalltalk
Model/View/Controller [<A HREF="bibfs-1.htm#krasner_mvc" tppabs="http://ultra/development/DesignPatterns/lowres/bibfs.htm#krasner_mvc" TARGET="_mainDisplayFrame">KP88</A>] was a Composite, and nearly every user interface
toolkit or framework has followed in its steps, including ET++ (with
its VObjects [<A HREF="bibfs-1.htm#et++" tppabs="http://ultra/development/DesignPatterns/lowres/bibfs.htm#et++" TARGET="_mainDisplayFrame">WGM88</A>]) and InterViews (Styles [<A HREF="bibfs-1.htm#InterViews3.1" tppabs="http://ultra/development/DesignPatterns/lowres/bibfs.htm#InterViews3.1" TARGET="_mainDisplayFrame">LCI+92</A>],
Graphics [<A HREF="bibfs-1.htm#interviews_graphic" tppabs="http://ultra/development/DesignPatterns/lowres/bibfs.htm#interviews_graphic" TARGET="_mainDisplayFrame">VL88</A>], and
Glyphs [<A HREF="bibfs-1.htm#interviews_glyphs" tppabs="http://ultra/development/DesignPatterns/lowres/bibfs.htm#interviews_glyphs" TARGET="_mainDisplayFrame">CL90</A>]). It's interesting to note that the
original View of Model/View/Controller had a set of subviews; in other words, View was
both the Component class and the Composite class. Release 4.0 of
Smalltalk-80 revised Model/View/Controller with a VisualComponent class that has
subclasses View and CompositeView.</P>
<A NAME="rtlsmall-use-comp"></A>
<A NAME="ssa"></A>
<P>The RTL Smalltalk compiler framework [<A HREF="bibfs-1.htm#RTLSystem92" tppabs="http://ultra/development/DesignPatterns/lowres/bibfs.htm#RTLSystem92" TARGET="_mainDisplayFrame">JML92</A>] uses the
Composite pattern extensively. RTLExpression is a Component class for
parse trees. It has subclasses, such as BinaryExpression, that contain
child RTLExpression objects. These classes define a composite
structure for parse trees. RegisterTransfer is the Component class
for a program's intermediate Single Static Assignment (SSA) form.
Leaf subclasses of RegisterTransfer define different static
assignments such as</P>
<UL>
<A NAME="auto1098"></A>
<LI>primitive assignments that perform an operation on two registers and
assign the result to a third;</LI>
<A NAME="auto1099"></A>
<P></P>
<A NAME="auto1100"></A>
<LI>an assignment with a source register but no destination register,
which indicates that the register is used after a routine returns; and</LI>
<A NAME="auto1101"></A>
<P></P>
<A NAME="auto1102"></A>
<LI>an assignment with a destination register but no source, which
indicates that the register is assigned before the routine starts.</LI>
</UL>
<A NAME="auto1103"></A>
<P>Another subclass, RegisterTransferSet, is a Composite class
for representing assignments that change several registers at once.</P>
<A NAME="auto1104"></A>
<P>Another example of this pattern occurs in the financial domain, where
a portfolio aggregates individual assets. You can support complex
aggregations of assets by implementing a portfolio as a Composite that
conforms to the interface of an individual
asset [<A HREF="bibfs-1.htm#birrer-egg_swaps" tppabs="http://ultra/development/DesignPatterns/lowres/bibfs.htm#birrer-egg_swaps" TARGET="_mainDisplayFrame">BE93</A>].</P>
<A NAME="auto1105"></A>
<P>The <A HREF="pat5bfs-1.htm" tppabs="http://ultra/development/DesignPatterns/lowres/pat5bfs.htm" TARGET="_mainDisplayFrame">Command (233)</A> pattern describes how Command objects
can be composed and sequenced with a MacroCommand Composite class.</P>
<A NAME="relatedpatterns"></A>
<H2><A HREF="#last"><IMG SRC="down3-1.gif" tppabs="http://ultra/development/DesignPatterns/lowres/gifsb/down3.gif" BORDER=0 ALT="next:
navigation"></A> Related Patterns</H2>
<A NAME="auto1106"></A>
<P>Often the component-parent link is used for a <A HREF="pat5afs-1.htm" tppabs="http://ultra/development/DesignPatterns/lowres/pat5afs.htm"
TARGET="_mainDisplayFrame">Chain of Responsibility (223)</A>.</P>
<A NAME="compcomposite"></A>
<P><A HREF="pat4dfs-1.htm" tppabs="http://ultra/development/DesignPatterns/lowres/pat4dfs.htm" TARGET="_mainDisplayFrame">Decorator (175)</A> is
often used with Composite. When decorators and composites are used
together, they will usually have a common parent class. So decorators
will have to support the Component interface with operations like
Add, Remove, and GetChild.</P>
<A NAME="auto1107"></A>
<P><A HREF="pat4ffs-1.htm" tppabs="http://ultra/development/DesignPatterns/lowres/pat4ffs.htm" TARGET="_mainDisplayFrame">Flyweight (195)</A>
lets you share components, but they can no longer refer to their
parents.</P>
<A NAME="auto1108"></A>
<P><A HREF="pat5dfs-1.htm" tppabs="http://ultra/development/DesignPatterns/lowres/pat5dfs.htm" TARGET="_mainDisplayFrame">Iterator (257)</A> can
be used to traverse composites.</P>
<A NAME="auto1109"></A>
<P><A HREF="pat5kfs-1.htm" tppabs="http://ultra/development/DesignPatterns/lowres/pat5kfs.htm" TARGET="_mainDisplayFrame">Visitor (331)</A>
localizes operations and behavior that would otherwise be distributed
across Composite and Leaf classes.</P>
<A NAME="last"></A>
<P><A HREF="#intent"><IMG SRC="up3-1.gif" tppabs="http://ultra/development/DesignPatterns/lowres/gifsb/up3.gif" BORDER=0></A><BR>
<A HREF="pat4dfs-1.htm" tppabs="http://ultra/development/DesignPatterns/lowres/pat4dfs.htm" TARGET="_mainDisplayFrame"><IMG SRC="rightar3-1.gif" tppabs="http://ultra/development/DesignPatterns/lowres/gifsb/rightar3.gif"
ALIGN=TOP BORDER=0></A> <A HREF="pat4dfs-1.htm" tppabs="http://ultra/development/DesignPatterns/lowres/pat4dfs.htm"
TARGET="_mainDisplayFrame">Decorator</A><BR>
<A HREF="pat4bfs-1.htm" tppabs="http://ultra/development/DesignPatterns/lowres/pat4bfs.htm" TARGET="_mainDisplayFrame"><IMG SRC="leftarr3-1.gif" tppabs="http://ultra/development/DesignPatterns/lowres/gifsb/leftarr3.gif"
ALIGN=TOP BORDER=0></A> <A HREF="pat4bfs-1.htm" tppabs="http://ultra/development/DesignPatterns/lowres/pat4bfs.htm"
TARGET="_mainDisplayFrame">Bridge</A>
</P>
<HR>
<A NAME="footnote2"></A>
<P><SUP>2</SUP>It's easy to forget to delete
the iterator once you're done with it. The Iterator pattern shows
how to guard against such bugs on
<A HREF="pat5dfs-1.htm#clean-up_proxy_for_iterators" tppabs="http://ultra/development/DesignPatterns/lowres/pat5dfs.htm#clean-up_proxy_for_iterators" TARGET="_mainDisplayFrame">page 266</A>.</P>
</BODY>
</HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -