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

📄 pat4a.htm

📁 Addison Wesley - Design Patterns - Elements of Reusable Object-Oriented Software
💻 HTM
📖 第 1 页 / 共 2 页
字号:
<SCRIPT>
function setFocus() {	
	if ((navigator.appName != "Netscape") && (parseFloat(navigator.appVersion) == 2)) {
	return;
	} else {
	self.focus();
	}
}
</SCRIPT><HTML>

<HEAD><TITLE>Adapter</TITLE></HEAD>

<BODY	BGCOLOR	= #FFFFFF
	TEXT = #000000
onLoad="setFocus()";
>

<A NAME="top"></A>
<A NAME="Adapter"></A>
<A NAME="intent"></A>
<H2><A HREF="#alsoknownas"><IMG SRC="gifsb/down3.gif" BORDER=0 ALT="next: 
Also Known As"></A> Intent</H2> 

<A NAME="auto1000"></A>
<P>Convert the interface of a class into another interface clients
expect.  Adapter lets classes work together that couldn't otherwise
because of incompatible interfaces.</P>

<A NAME="alsoknownas"><A>
<H2><A HREF="#motivation"><IMG SRC="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="gifsb/down3.gif" BORDER=0 
ALT="next: Applicability"></A> Motivation</H2> 

<A NAME="auto1002"></A>
<P>Sometimes a toolkit class that's designed for reuse isn't reusable
only because its interface doesn't match the domain-specific interface
an application requires.</P>

<A NAME="auto1003"></A>
<P>Consider for example a drawing editor that lets users draw and arrange
graphical elements (lines, polygons, text, etc.) into pictures and
diagrams.  The drawing editor's key abstraction is the graphical
object, which has an editable shape and can draw itself.  The
interface for graphical objects is defined by an abstract class called
Shape.  The editor defines a subclass of Shape for each kind of
graphical object: a LineShape class for lines, a PolygonShape class
for polygons, and so forth.</P>

<A NAME="textshape"></A>
<A NAME="textview"></A>
<P>Classes for elementary geometric shapes like LineShape and
PolygonShape are rather easy to implement, because their drawing and
editing capabilities are inherently limited.  But a TextShape subclass
that can display and edit text is considerably more difficult to
implement, since even basic text editing involves complicated screen
update and buffer management.  Meanwhile, an off-the-shelf user
interface toolkit might already provide a sophisticated TextView class
for displaying and editing text.  Ideally we'd like to reuse TextView
to implement TextShape, but the toolkit wasn't designed with Shape
classes in mind.  So we can't use TextView and Shape objects
interchangeably.</P>

<A NAME="auto1004"></A>
<P>How can existing and unrelated classes like TextView work in an
application that expects classes with a different and incompatible
interface?  We could change the TextView class so that it conforms to
the Shape interface, but that isn't an option unless we have the
toolkit's source code.  Even if we did, it wouldn't make sense to
change TextView; the toolkit shouldn't have to adopt domain-specific
interfaces just to make one application work.</P>

<A NAME="adapterdef"></A>
<P>Instead, we could define TextShape so that it <EM>adapts</EM> the
TextView interface to Shape's.  We can do this in one of two ways: (1)
by inheriting Shape's interface and TextView's implementation or (2)
by composing a TextView instance within a TextShape and implementing
TextShape in terms of TextView's interface.  These two approaches
correspond to the class and object versions of the Adapter pattern.
We call TextShape an <STRONG>adapter</STRONG>.</P>

<A NAME="shape-140c"></A>
<P ALIGN=CENTER><IMG SRC="Pictures/adapt105.gif"></P>

<A NAME="auto1005"></A>
<P>This diagram illustrates the object adapter case. It shows how
BoundingBox requests, declared in class Shape, are converted to
GetExtent requests defined in TextView.  Since TextShape adapts
TextView to the Shape interface, the drawing editor can reuse the
otherwise incompatible TextView class.</P>

<A NAME="auto1006"></A>
<P>Often the adapter is responsible for functionality the adapted class
doesn't provide.  The diagram shows how an adapter can fulfill
such responsibilities.  The user should be able to "drag" every
Shape object to a new location interactively, but TextView isn't
designed to do that.  TextShape can add this missing functionality by
implementing Shape's CreateManipulator operation, which returns an
instance of the appropriate Manipulator subclass.</P>

<A NAME="auto1007"></A>
<P>Manipulator is an abstract class for objects that know how to animate
a Shape in response to user input, like dragging the shape to a new
location.  There are subclasses of Manipulator for different shapes;
TextManipulator, for example, is the corresponding subclass for
TextShape.  By returning a TextManipulator instance, TextShape adds
the functionality that TextView lacks but Shape requires.</P>

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

<A NAME="auto1008"></A>
<P>Use the Adapter pattern when</P>

<UL>

<A NAME="auto1009"></A>
<LI>you want to use an existing class, and its interface does not
match the one you need.</P>

<A NAME="auto1010"></A>
<LI>you want to create a reusable class that cooperates with unrelated or
unforeseen classes, that is, classes that don't necessarily have
compatible interfaces.</P>

<A NAME="auto1011"></A>
<LI><EM>(object adapter only)</EM>
you need to use several existing subclasses, but it's impractical to
adapt their interface by subclassing every one.  An object adapter can
adapt the interface of its parent class.</P>

</UL>

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

<A NAME="141c"></A>
<P>A class adapter uses multiple inheritance to adapt one interface
to another:</P>

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

<A NAME="141o"></A>
<P>An object adapter relies on object composition:</P>

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

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

<UL>

<A NAME="auto1012"></A>
<LI><B>Target</B> (Shape)

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

<UL>

    <A NAME="auto1014"></A>
<LI>defines the domain-specific interface that Client uses.</LI>

</UL>

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

<A NAME="auto1016"></A>
<LI><B>Client</B> (DrawingEditor)

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

<UL>

    <A NAME="auto1018"></A>
<LI>collaborates with objects conforming to the Target interface.</LI>

</UL>

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

<A NAME="auto1020"></A>
<LI><B>Adaptee</B> (TextView)

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

<UL>

    <A NAME="auto1022"></A>
<LI>defines an existing interface that needs adapting.</LI>

</UL>

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

<A NAME="auto1024"></A>
<LI><B>Adapter</B> (TextShape)

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

<UL>

    <A NAME="auto1026"></A>
<LI>adapts the interface of Adaptee to the Target interface.</LI>

</UL>

</UL>

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

<UL>

<A NAME="auto1027"></A>
<LI>Clients call operations on an Adapter instance.  In turn, the adapter
calls Adaptee operations that carry out the request.</LI>

</UL>

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

<A NAME="auto1028"></A>
<P>Class and object adapters have different trade-offs.  A class adapter</P>

<UL>

<A NAME="auto1029"></A>
<LI>adapts Adaptee to Target by committing to a concrete Adapter class.
As a consequence, a class adapter won't work when we want to adapt a
class <EM>and</EM> all its subclasses.</LI>

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

<A NAME="auto1031"></A>
<LI>lets Adapter override some of Adaptee's behavior, since
Adapter is a subclass of Adaptee.</LI>

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

<A NAME="auto1033"></A>
<LI>introduces only one object, and no additional pointer indirection is
needed to get to the adaptee.</LI>

</UL>

<A NAME="auto1034"></A>
<P>An object adapter</P>

<UL>

<A NAME="auto1035"></A>
<LI>lets a single Adapter work with many Adaptees&#151;that is, the Adaptee
itself and all of its subclasses (if any).  The Adapter can also add
functionality to all Adaptees at once.</LI>

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

<A NAME="auto1037"></A>
<LI>makes it harder to override Adaptee behavior.  It will require
subclassing Adaptee and making Adapter refer to the subclass
rather than the Adaptee itself.</LI>

</UL>

<A NAME="auto1038"></A>
<P>Here are other issues to consider when using the Adapter pattern:</P>

<OL>

<A NAME="pluggable"></A>
<LI><EM>How much adapting does Adapter do?</EM>
Adapters vary in the amount of work they do to adapt Adaptee to
the Target interface.  There is a spectrum of possible work, from
simple interface conversion&#151;for example, changing the names of
operations&#151;to supporting an entirely different set of operations.
The amount of work Adapter does depends on how similar the Target
interface is to Adaptee's.</LI>

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

<A NAME="deleg-plug"></A>
<LI><EM>Pluggable adapters.</EM>
A class is more reusable when you minimize the assumptions other
classes must make to use it.  By building interface adaptation into a
class, you eliminate the assumption that other classes see the same
interface.  Put another way, interface adaptation lets us incorporate
our class into existing systems that might expect different interfaces
to the class.
ObjectWorks\Smalltalk [<A HREF="bibfs.htm#parcplace_smalltalk" TARGET="_mainDisplayFrame">Par90</A>] uses the term
<STRONG>pluggable adapter</STRONG> to describe classes with built-in
interface adaptation.

<A NAME="treedisplay"></A>
<P>Consider a TreeDisplay widget that can display tree structures
graphically.  If this were a special-purpose widget for use in just one
application, then we might require the objects that it displays to
have a specific interface; that is, all must descend from a Tree
abstract class.  But if we wanted to make TreeDisplay more reusable
(say we wanted to make it part of a toolkit of useful widgets), then
that requirement would be unreasonable.  Applications will define
their own classes for tree structures.  They shouldn't be forced to
use our Tree abstract class.  Different tree structures will have
different interfaces.</P>

<A NAME="auto1040"></A>
<P>In a directory hierarchy, for example, children might be accessed with
a GetSubdirectories operation, whereas in an inheritance hierarchy,
the corresponding operation might be called GetSubclasses.  A reusable
TreeDisplay widget must be able to display both kinds of hierarchies
even if they use different interfaces.  In other words, the
TreeDisplay should have interface adaptation built into it.</P>

<A NAME="auto1041"></A>
<P>We'll look at different ways to build interface adaptation into classes
in the Implementation section.</P>

</LI>

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

<A NAME="twoway"></A>
<LI><EM>Using two-way adapters to provide transparency.</EM>
A potential problem with adapters is that they aren't transparent to
all clients.  An adapted object no longer conforms to the Adaptee
interface, so it can't be used as is wherever an Adaptee object can.
<STRONG>Two-way adapters</STRONG> can provide such transparency.
Specifically, they're useful when two different clients need to view
an object differently.

<A NAME="qoca-use-adapt"></A>
<A NAME="unidraw-use-adapt"></A>
<P>Consider the two-way adapter that integrates Unidraw, a graphical
editor framework [<A HREF="bibfs.htm#unidraw_framework" TARGET="_mainDisplayFrame">VL90</A>], and QOCA, a
constraint-solving toolkit [<A HREF="bibfs.htm#qoca" TARGET="_mainDisplayFrame">HHMV92</A>].  Both systems have classes
that represent variables explicitly: Unidraw has StateVariable, and
QOCA has ConstraintVariable.  To make Unidraw work with QOCA,
ConstraintVariable must be adapted to StateVariable; to let QOCA
propagate solutions to Unidraw, StateVariable must be adapted to
ConstraintVariable.</P>

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

<A NAME="auto1043"></A>
<P>The solution involves a two-way class adapter ConstraintStateVariable,
a subclass of both StateVariable and ConstraintVariable, that adapts
the two interfaces to each other.  Multiple inheritance is a viable
solution in this case because the interfaces of the adapted classes
are substantially different. The two-way class adapter conforms to
both of the adapted classes and can work in either system.</P>

</LI>

</OL>

<A NAME="implementation"></A>
<H2><A HREF="#samplecode"><IMG SRC="gifsb/down3.gif" BORDER=0 ALT="next: 
Sample Code"></A> Implementation</H2> 

<A NAME="auto1044"></A>
<P>Although the implementation of Adapter is usually straightforward,
here are some issues to keep in mind:</P>

<OL>

<A NAME="auto1045"></A>
<LI><EM>Implementing class adapters in C++.</EM>
In a C++ implementation of a class adapter, Adapter
would inherit publicly from Target and privately from Adaptee.
Thus Adapter would be a subtype of Target but not of Adaptee.</LI>

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

<A NAME="plugap-imp"></A>
<LI><EM>Pluggable adapters.</EM>
Let's look at three ways to implement pluggable adapters for the
TreeDisplay widget described earlier, which can lay out and display a
hierarchical structure automatically.

⌨️ 快捷键说明

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