📄 pat4f.htm
字号:
<HTML><HEAD> <TITLE>Flyweight</TITLE></HEAD>
<BODY BGCOLOR = #FFFFFF
TEXT = #000000
>
<A NAME="top"></A>
<A NAME="Flyweight"></A>
<A NAME="intent"></A>
<H2><A HREF="#motivation"><IMG SRC="gifsb/down3.gif" BORDER=0></A> Intent</H2>
<A NAME="auto1000"></A>
<P>Use sharing to support large numbers of fine-grained objects efficiently.</P>
<A NAME="motivation"></A>
<H2><A HREF="#applicability"><IMG SRC="gifsb/down3.gif" BORDER=0></A> Motivation</H2>
<A NAME="auto1001"></A>
<P>Some applications could benefit from using objects throughout their
design, but a naive implementation would be prohibitively expensive.</P>
<A NAME="auto1002"></A>
<P>For example, most document editor implementations have text formatting
and editing facilities that are modularized to some extent.
Object-oriented document editors typically use objects to represent
embedded elements like tables and figures. However, they usually stop
short of using an object for each character in the document, even
though doing so would promote flexibility at the finest levels in the
application. Characters and embedded elements could then be treated
uniformly with respect to how they are drawn and formatted. The
application could be extended to support new character sets without
disturbing other functionality. The application's object structure
could mimic the document's physical structure. The following diagram
shows how a document editor can use objects to represent characters.</P>
<P ALIGN=CENTER><IMG SRC="Pictures/flywe055.gif"></P>
<A NAME="auto1003"></A>
<P>The drawback of such a design is its cost. Even moderate-sized
documents may require hundreds of thousands of character objects,
which will consume lots of memory and may incur unacceptable run-time
overhead. The Flyweight pattern describes how to share objects to
allow their use at fine granularities without prohibitive cost.</P>
<A NAME="def-flywt"></A>
<A NAME="def-extrinsicstate"></A>
<A NAME="def-intrinsicstate"></A>
<P>A <STRONG>flyweight</STRONG> is a shared object that can be used in
multiple contexts simultaneously. The flyweight acts as an independent
object in each context—it's indistinguishable from an instance of
the object that's not shared. Flyweights cannot make assumptions about
the context in which they operate. The key concept here is the
distinction between <STRONG>intrinsic</STRONG> and <STRONG>extrinsic</STRONG>
state. Intrinsic state is stored in the flyweight; it consists of
information that's independent of the flyweight's context, thereby
making it sharable. Extrinsic state depends on and varies with the
flyweight's context and therefore can't be shared. Client objects are
responsible for passing extrinsic state to the flyweight when it needs
it.</P>
<A NAME="auto1004"></A>
<P>Flyweights model concepts or entities that are normally too plentiful
to represent with objects. For example, a document editor can create a
flyweight for each letter of the alphabet. Each flyweight stores a
character code, but its coordinate position in the document and its
typographic style can be determined from the text layout algorithms
and formatting commands in effect wherever the character appears. The
character code is intrinsic state, while the other information is
extrinsic.</P>
<A NAME="auto1005"></A>
<P>Logically there is an object for every occurrence of a given character in
the document:</P>
<A NAME="flywt-eg-logic"></A>
<P ALIGN=CENTER><IMG SRC="Pictures/flywe054.gif"></P>
<A NAME="auto1006"></A>
<P>Physically, however, there is one shared flyweight object per
character, and it appears in different contexts in the document
structure. Each occurrence of a particular character object refers to
the same instance in the shared pool of flyweight objects:</P>
<P ALIGN=CENTER><IMG SRC="Pictures/flywe052.gif"></P>
<A NAME="auto1007"></A>
<P>The class structure for these objects is shown next. Glyph is the
abstract class for graphical objects, some of which may be flyweights.
Operations that may depend on extrinsic state have it passed to them
as a parameter. For example, Draw and Intersects must know which
context the glyph is in before they can do their job.</P>
<P ALIGN=CENTER><IMG SRC="Pictures/flywe053.gif"></P>
<A NAME="auto1008"></A>
<P>A flyweight representing the letter "a" only stores the
corresponding character code; it doesn't need to store its location or
font. Clients supply the context-dependent information that the
flyweight needs to draw itself. For example, a Row glyph knows where
its children should draw themselves so that they are tiled
horizontally. Thus it can pass each child its location in the draw
request.</P>
<A NAME="auto1009"></A>
<P>Because the number of different character objects is far less than the
number of characters in the document, the total number of objects is
substantially less than what a naive implementation would use. A
document in which all characters appear in the same font and color
will allocate on the order of 100 character objects (roughly the size
of the ASCII character set) regardless of the document's length. And
since most documents use no more than 10 different font-color
combinations, this number won't grow appreciably in practice. An
object abstraction thus becomes practical for individual characters.</P>
<A NAME="applicability"></A>
<H2><A HREF="#structure"><IMG SRC="gifsb/down3.gif" BORDER=0></A> Applicability</H2>
<A NAME="auto1010"></A>
<P>The Flyweight pattern's effectiveness depends heavily on how and where
it's used. Apply the Flyweight pattern when <EM>all</EM> of the following
are true:</P>
<UL>
<A NAME="auto1011"></A>
<LI>An application uses a large number of objects.</LI>
<A NAME="auto1012"></A>
<P></P>
<A NAME="auto1013"></A>
<LI>Storage costs are high because of the sheer quantity of objects.</LI>
<A NAME="auto1014"></A>
<P></P>
<A NAME="auto1015"></A>
<LI>Most object state can be made extrinsic.</LI>
<A NAME="auto1016"></A>
<P></P>
<A NAME="auto1017"></A>
<LI>Many groups of objects may be replaced by relatively few shared
objects once extrinsic state is removed.</LI>
<A NAME="auto1018"></A>
<P></P>
<A NAME="auto1019"></A>
<LI>The application doesn't depend on object identity. Since flyweight
objects may be shared, identity tests will return true for conceptually
distinct objects.</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/flywe050.gif"></P>
<A NAME="auto1020"></A>
<P>The following object diagram shows how flyweights are shared:</P>
<P ALIGN=CENTER><IMG SRC="Pictures/flywe051.gif"></P>
<A NAME="participants"></A>
<H2><A HREF="#collaborations"><IMG SRC="gifsb/down3.gif" BORDER=0></A>
Participants</H2>
<UL>
<A NAME="auto1021"></A>
<LI><B>Flyweight</B>
<A NAME="auto1022"></A>
<P></P>
<UL>
<A NAME="auto1023"></A>
<LI>declares an interface through which flyweights can
receive and act on extrinsic state.</LI>
</UL>
<A NAME="auto1024"></A>
<P></P>
<A NAME="auto1025"></A>
<LI><B>ConcreteFlyweight</B> (Character)</LI>
<A NAME="auto1026"></A>
<P></P>
<UL>
<A NAME="auto1027"></A>
<LI>implements the Flyweight interface and adds storage for
intrinsic state, if any. A ConcreteFlyweight object must be sharable. Any
state it stores must be intrinsic; that is, it must be
independent of the ConcreteFlyweight object's context.</LI>
</UL>
<A NAME="auto1028"></A>
<P></P>
<A NAME="unsharconcflywt"></A>
<LI><B>UnsharedConcreteFlyweight</B> (Row, Column)</LI>
<A NAME="auto1029"></A>
<P></P>
<UL>
<A NAME="auto1030"></A>
<LI>not all Flyweight subclasses need to be shared. The
Flyweight interface <EM>enables</EM> sharing; it doesn't enforce it.
It's common for UnsharedConcreteFlyweight objects to have
ConcreteFlyweight objects as children at
some level in the flyweight object structure
(as the Row and Column classes have).</LI>
</UL>
<A NAME="auto1031"></A>
<P></P>
<A NAME="flywtfact-part"></A>
<LI><B>FlyweightFactory</B></LI>
<A NAME="auto1032"></A>
<P></P>
<UL>
<A NAME="auto1033"></A>
<LI>creates and manages flyweight objects.</LI>
<A NAME="auto1034"></A>
<P><!-- extra space --></P>
<A NAME="auto1035"></A>
<LI>ensures that flyweights are shared properly.
When a client requests a flyweight, the FlyweightFactory object supplies
an existing instance or creates one, if none exists.
</UL>
<A NAME="auto1036"></A>
<P></P>
<A NAME="auto1037"></A>
<LI><B>Client</B></LI>
<A NAME="auto1038"></A>
<P></P>
<UL>
<A NAME="auto1039"></A>
<LI>maintains a reference to flyweight(s).</LI>
<A NAME="auto1040"></A>
<P><!-- extra space --></P>
<A NAME="auto1041"></A>
<LI>computes or stores the extrinsic state of flyweight(s).</LI>
</UL>
</UL>
<A NAME="collaborations"></A>
<H2><A HREF="#consequences"><IMG SRC="gifsb/down3.gif" BORDER=0></A> Collaborations</H2>
<UL>
<A NAME="auto1042"></A>
<LI>State that a flyweight needs to function must be characterized as
either intrinsic or extrinsic. Intrinsic state is stored in the
ConcreteFlyweight object; extrinsic state is stored or computed by
Client objects. Clients pass this state to the flyweight when
they invoke its operations.</LI>
<A NAME="auto1043"></A>
<P></P>
<A NAME="auto1044"></A>
<LI>Clients should not instantiate ConcreteFlyweights directly. Clients
must obtain ConcreteFlyweight objects exclusively from the
FlyweightFactory object to ensure they are shared properly.</LI>
</UL>
<A NAME="consequences"></A>
<H2><A HREF="#implementation"><IMG SRC="gifsb/down3.gif" BORDER=0></A> Consequences</H2>
<A NAME="auto1045"></A>
<P>Flyweights may introduce run-time costs associated with transferring,
finding, and/or computing extrinsic state, especially if it was
formerly stored as intrinsic state. However, such costs are offset by
space savings, which increase as more flyweights are shared.</P>
<A NAME="auto1046"></A>
<P>Storage savings are a function of several factors:</P>
<UL>
<A NAME="auto1047"></A>
<LI>the reduction in the total number of instances that comes from
sharing</LI>
<A NAME="auto1048"></A>
<P></P>
<A NAME="auto1049"></A>
<LI>the amount of intrinsic state per object</LI>
<A NAME="auto1050"></A>
<P></P>
<A NAME="auto1051"></A>
<LI>whether extrinsic state is computed or stored.</LI>
</UL>
<A NAME="auto1052"></A>
<P>The more flyweights are shared, the greater the storage savings. The
savings increase with the amount of shared state. The greatest
savings occur when the objects use substantial quantities of both
intrinsic and extrinsic state, and the extrinsic state can be computed
rather than stored. Then you save on storage in two ways: Sharing
reduces the cost of intrinsic state, and you trade extrinsic state for
computation time.</P>
<A NAME="flywt-w-compst"></A>
<P>The Flyweight pattern is often combined with the
<A HREF="pat4cfs.htm" TARGET="_mainDisplayFrame">Composite (163)</A> pattern to represent a hierarchical
structure as a graph with shared leaf nodes. A consequence of sharing
is that flyweight leaf nodes cannot store a pointer to their parent.
Rather, the parent pointer is passed to the flyweight as part of its
extrinsic state. This has a major impact on how the objects in the
hierarchy communicate with each other.</P>
<A NAME="implementation"></A>
<H2><A HREF="#samplecode"><IMG SRC="gifsb/down3.gif" BORDER=0></A> Implementation</H2>
<A NAME="auto1053"></A>
<P>Consider the following issues when implementing the Flyweight pattern:</P>
<OL>
<A NAME="auto1054"></A>
<LI><EM>Removing extrinsic state.</EM>
The pattern's applicability is determined largely by how easy it is to
identify extrinsic state and remove it from shared objects. Removing
extrinsic state won't help reduce storage costs if there are as many
different kinds of extrinsic state as there are objects before
sharing. Ideally, extrinsic state can be computed from a separate
object structure, one with far smaller storage requirements.
<A NAME="auto1055"></A>
<P>In our document editor, for example, we can store a map of typographic
information in a separate structure rather than store the font and
type style with each character object. The map keeps track of runs of
characters with the same typographic attributes. When a character
draws itself, it receives its typographic attributes as a side-effect
of the draw traversal. Because documents normally use just a few
different fonts and styles, storing this information externally to
each character object is far more efficient than storing it
internally.</P>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -