📄 pat4d-1.htm
字号:
<SCRIPT>
function setFocus() {
if ((navigator.appName != "Netscape") && (parseFloat(navigator.appVersion) == 2)) {
return;
} else {
self.focus();
}
}
</SCRIPT><HTML><HEAD> <TITLE>Decorator</TITLE></HEAD>
<BODY BGCOLOR = #FFFFFF
TEXT = #000000
onLoad="setFocus()";
>
<A NAME="top"></A>
<A NAME="Decorator"></A>
<A NAME="intent"></A>
<H2><A HREF="#alsoknownas"><IMG SRC="down3-1.gif" tppabs="http://ultra/development/DesignPatterns/lowres/gifsb/down3.gif" BORDER=0 ALT="next:
Also Known As"></A> Intent</H2>
<A NAME="auto1000"></A>
<P>Attach additional responsibilities to an object dynamically.
Decorators provide a flexible alternative to subclassing for extending
functionality.</P>
<A NAME="alsoknownas"><A>
<H2><A HREF="#motivation"><IMG SRC="down3-1.gif" tppabs="http://ultra/development/DesignPatterns/lowres/gifsb/down3.gif" BORDER=0 ALT="next:
Motivation"></A> Also Known As</H2>
<A NAME="auto1001"></A>
<P>Wrapper</P>
<A NAME="motivation"></A>
<H2><A HREF="#applicability"><IMG SRC="down3-1.gif" tppabs="http://ultra/development/DesignPatterns/lowres/gifsb/down3.gif" BORDER=0
ALT="next: Applicability"></A> Motivation</H2>
<A NAME="auto1002"></A>
<P>Sometimes we want to add responsibilities to individual objects, not
to an entire class. A graphical user interface toolkit, for example,
should let you add properties like borders or behaviors like scrolling
to any user interface component.</P>
<A NAME="auto1003"></A>
<P>One way to add responsibilities is with inheritance. Inheriting a
border from another class puts a border around every subclass
instance. This is inflexible, however, because the choice of border
is made statically. A client can't control how and when to decorate
the component with a border.</P>
<A NAME="dec-175"></A>
<P>A more flexible approach is to enclose the component in another object
that adds the border. The enclosing object is called a
<STRONG>decorator</STRONG>. The decorator conforms to the interface of the
component it decorates so that its presence is transparent to the
component's clients. The decorator forwards requests to the component
and may perform additional actions (such as drawing a border) before
or after forwarding. Transparency lets you nest decorators
recursively, thereby allowing an unlimited number of added
responsibilities.</P>
<P ALIGN=CENTER><IMG SRC="decor066-1.gif" tppabs="http://ultra/development/DesignPatterns/lowres/Pictures/decor066.gif"></P>
<A NAME="auto1004"></A>
<P>For example, suppose we have a TextView object that displays text in a
window. TextView has no scroll bars by default, because we might not
always need them. When we do, we can use a ScrollDecorator to add
them. Suppose we also want to add a thick black border around the
TextView. We can use a BorderDecorator to add this as well. We
simply compose the decorators with the TextView to produce the desired
result.</P>
<A NAME="auto1005"></A>
<P>The following object diagram shows how to compose a TextView object
with BorderDecorator and ScrollDecorator objects to produce a
bordered, scrollable text view:</P>
<A NAME="scrolldecorator-176o"></A>
<A NAME="textview-176o"></A>
<P ALIGN=CENTER><IMG SRC="decor065-1.gif" tppabs="http://ultra/development/DesignPatterns/lowres/Pictures/decor065.gif"></P>
<A NAME="auto1006"></A>
<P>The ScrollDecorator and BorderDecorator classes are subclasses of
Decorator, an abstract class for visual components that decorate other
visual components.</P>
<A NAME="dec-176"></A>
<A NAME="scrolldecorator-176c"></A>
<A NAME="textview-176c"></A>
<P ALIGN=CENTER><IMG SRC="decor067-1.gif" tppabs="http://ultra/development/DesignPatterns/lowres/Pictures/decor067.gif"></P>
<A NAME="visual-comp"></A>
<P>VisualComponent is the abstract class for visual objects. It
defines their drawing and event handling interface. Note how the
Decorator class simply forwards draw requests to its component,
and how Decorator subclasses can extend this operation.</P>
<A NAME="auto1007"></A>
<P>Decorator subclasses are free to add operations for specific
functionality. For example, ScrollDecorator's ScrollTo operation lets
other objects scroll the interface <EM>if</EM> they know there happens to
be a ScrollDecorator object in the interface. The important aspect of
this pattern is that it lets decorators appear anywhere a
VisualComponent can. That way clients generally can't tell the
difference between a decorated component and an undecorated one, and
so they don't depend at all on the decoration.</P>
<A NAME="applicability"></A>
<H2><A HREF="#structure"><IMG SRC="down3-1.gif" tppabs="http://ultra/development/DesignPatterns/lowres/gifsb/down3.gif" BORDER=0 ALT="next:
Structure"></A> Applicability</H2>
<A NAME="auto1008"></A>
<P>Use Decorator</P>
<UL>
<A NAME="auto1009"></A>
<LI>to add responsibilities to individual objects
dynamically and transparently, that is, without affecting other
objects.</LI>
<A NAME="auto1010"></A>
<P></P>
<A NAME="auto1011"></A>
<LI>for responsibilities that can be withdrawn.</LI>
<A NAME="auto1012"></A>
<P></P>
<A NAME="auto1013"></A>
<LI>when extension by subclassing is impractical. Sometimes a large
number of independent extensions are possible and would produce an
explosion of subclasses to support every combination. Or a class
definition may be hidden or otherwise unavailable for subclassing.</LI>
</UL>
<A NAME="structure"></A>
<H2><A HREF="#participants"><IMG SRC="down3-1.gif" tppabs="http://ultra/development/DesignPatterns/lowres/gifsb/down3.gif" BORDER=0 ALT="next:
Participants"></A> Structure</H2>
<P ALIGN=CENTER><IMG SRC="decor064-1.gif" tppabs="http://ultra/development/DesignPatterns/lowres/Pictures/decor064.gif"></P>
<A NAME="participants"></A>
<A NAME="participants"></A>
<H2><A HREF="#collaborations"><IMG SRC="down3-1.gif" tppabs="http://ultra/development/DesignPatterns/lowres/gifsb/down3.gif" BORDER=0
ALT="next: Collaborations"></A> Participants</H2>
<UL>
<A NAME="auto1014"></A>
<LI><B>Component</B> (VisualComponent)</LI>
<A NAME="auto1015"></A>
<P></P>
<UL>
<A NAME="auto1016"></A>
<LI>defines the interface for objects that can have
responsibilities added to them dynamically.</LI>
</UL>
<A NAME="auto1017"></A>
<P></P>
<A NAME="auto1018"></A>
<LI><B>ConcreteComponent</B> (TextView)</LI>
<A NAME="auto1019"></A>
<P></P>
<UL>
<A NAME="auto1020"></A>
<LI>defines an object to which additional responsibilities
can be attached.</LI>
</UL>
<A NAME="auto1021"></A>
<P></P>
<A NAME="dec-part"></A>
<LI><B>Decorator</B></LI>
<A NAME="auto1022"></A>
<P></P>
<UL>
<A NAME="auto1023"></A>
<LI>maintains a reference to a Component object and defines an interface
that conforms to Component's interface.</LI>
</UL>
<A NAME="auto1024"></A>
<P></P>
<A NAME="auto1025"></A>
<LI><B>ConcreteDecorator</B> (BorderDecorator, ScrollDecorator)</LI>
<A NAME="auto1026"></A>
<P></P>
<UL>
<A NAME="auto1027"></A>
<LI>adds responsibilities to the component.</LI>
</UL>
</UL>
<A NAME="collaborations"></A>
<H2><A HREF="#consequences"><IMG SRC="down3-1.gif" tppabs="http://ultra/development/DesignPatterns/lowres/gifsb/down3.gif" BORDER=0
ALT="next: Consequences"></A> Collaborations</H2>
<UL>
<A NAME="auto1028"></A>
<LI>Decorator forwards requests to its Component object. It may optionally
perform additional operations before and after forwarding the request.</LI>
</UL>
<A NAME="consequences"></A>
<H2><A HREF="#implementation"><IMG SRC="down3-1.gif" tppabs="http://ultra/development/DesignPatterns/lowres/gifsb/down3.gif" BORDER=0
ALT="next: Implementation"></A> Consequences</H2>
<A NAME="auto1029"></A>
<P>The Decorator pattern has at least two key benefits and two
liabilities:</P>
<OL>
<A NAME="auto1030"></A>
<LI><EM>More flexibility than static inheritance.</EM>
The Decorator pattern provides a more flexible way to add
responsibilities to objects than can be had with static (multiple)
inheritance. With decorators, responsibilities can be added and
removed at run-time simply by attaching and detaching them. In
contrast, inheritance requires creating a new class for each
additional responsibility (e.g., BorderedScrollableTextView,
BorderedTextView). This gives rise to many classes and increases the
complexity of a system. Furthermore, providing different Decorator
classes for a specific Component class lets you mix and match
responsibilities.
<A NAME="auto1031"></A>
<P>Decorators also make it easy to add a property twice. For example, to
give a TextView a double border, simply attach two
BorderDecorators. Inheriting from a Border class twice is error-prone
at best.</P>
</LI>
<A NAME="auto1032"></A>
<P></P>
<A NAME="auto1033"></A>
<LI><EM>Avoids feature-laden classes high up in the hierarchy.</EM>
Decorator offers a pay-as-you-go approach to adding responsibilities.
Instead of trying to support all foreseeable features in a complex,
customizable class, you can define a simple class and add functionality
incrementally with Decorator objects. Functionality can be composed from
simple pieces. As a result, an application needn't pay for features
it doesn't use. It's also easy to define new kinds of Decorators
independently from the classes of objects they extend, even for
unforeseen extensions. Extending a complex class tends to expose
details unrelated to the responsibilities you're adding.</LI>
<A NAME="auto1034"></A>
<P></P>
<A NAME="auto1035"></A>
<LI><EM>A decorator and its component aren't identical.</EM>
A decorator acts as a transparent enclosure. But from an object
identity point of view, a decorated component is not identical to the
component itself. Hence you shouldn't rely on object identity when
you use decorators.</LI>
<A NAME="auto1036"></A>
<P></P>
<A NAME="auto1037"></A>
<LI><EM>Lots of little objects.</EM>
A design that uses Decorator often results in systems composed of
lots of little objects that all look alike. The objects differ only
in the way they are interconnected, not in their class or in the value
of their variables. Although these systems are easy to customize
by those who understand them, they can be hard to learn and debug.</LI>
</OL>
<A NAME="implementation"></A>
<H2><A HREF="#samplecode"><IMG SRC="down3-1.gif" tppabs="http://ultra/development/DesignPatterns/lowres/gifsb/down3.gif" BORDER=0 ALT="next:
Sample Code"></A> Implementation</H2>
<A NAME="auto1038"></A>
<P>Several issues should be considered when applying the Decorator pattern:</P>
<OL>
<A NAME="auto1039"></A>
<LI><EM>Interface conformance.</EM>
A decorator object's interface must conform to the interface of the
component it decorates. ConcreteDecorator classes must therefore
inherit from a common class (at least in C++).</LI>
<A NAME="auto1040"></A>
<P></P>
<A NAME="auto1041"></A>
<LI><EM>Omitting the abstract Decorator class.</EM>
There's no need to define an abstract Decorator class when you only
need to add one responsibility. That's often the case when you're
dealing with an existing class hierarchy rather than designing a new
one. In that case, you can merge Decorator's responsibility for
forwarding requests to the component into the ConcreteDecorator.</LI>
<A NAME="auto1042"></A>
<P></P>
<A NAME="lightvsheavy"></A>
<LI><EM>Keeping Component classes lightweight.</EM>
To ensure a conforming interface, components and decorators must
descend from a common Component class. It's important to keep this
common class lightweight; that is, it should focus on defining an
interface, not on storing data. The definition of the data
representation should be deferred to subclasses; otherwise the
complexity of the Component class might make the decorators too
heavyweight to use in quantity. Putting a lot of functionality into
Component also increases the probability that concrete subclasses will
pay for features they don't need.</LI>
<A NAME="auto1043"></A>
<P></P>
<A NAME="dec-strat"></A>
<A NAME="strat-vs-decor"></A>
<LI><EM>Changing the skin of an object versus changing its guts.</EM>
We can think of a decorator as a skin over an object that changes its
behavior. An alternative is to change the object's guts.
The <A HREF="pat5ifs-1.htm" tppabs="http://ultra/development/DesignPatterns/lowres/pat5ifs.htm" TARGET="_mainDisplayFrame">Strategy (315)</A> pattern is a good example of a pattern for
changing the guts.
<A NAME="auto1044"></A>
<P>Strategies are a better choice in situations where the Component class
is intrinsically heavyweight, thereby making the Decorator pattern too
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -