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

📄 pat4b.htm

📁 Design Pattern 设计模式
💻 HTM
📖 第 1 页 / 共 2 页
字号:
<SCRIPT>
function setFocus() {	
	if ((navigator.appName != "Netscape") && (parseFloat(navigator.appVersion) == 2)) {
	return;
	} else {
	self.focus();
	}
}
</SCRIPT><HTML><HEAD>	<TITLE>Bridge</TITLE></HEAD><BODY	BGCOLOR	= #FFFFFF	TEXT = #000000
onLoad="setFocus()";><A NAME="top"></A><A NAME="Bridge"></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>Decouple an abstraction from its implementation so that the twocan vary independently.</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>Handle/Body</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>When an abstraction can have one of several possible implementations,the usual way to accommodate them is to use inheritance. An abstractclass defines the interface to the abstraction, and concretesubclasses implement it in different ways. But this approach isn'talways flexible enough.  Inheritance binds an implementation to theabstraction permanently, which makes it difficult to modify, extend,and reuse abstractions and implementations independently.</P><A NAME="pmwindow"></A><A NAME="present-manage"></A><A NAME="xwindowsys"></A><A NAME="xiconwindow"></A><A NAME="xwindow"></A><P>Consider the implementation of a portable Window abstraction in a userinterface toolkit. This abstraction should enable us to writeapplications that work on both the X Window System and IBM'sPresentation Manager (PM), for example. Using inheritance, we coulddefine an abstract class Window and subclasses XWindow and PMWindowthat implement the Window interface for the different platforms. Butthis approach has two drawbacks:</P><OL><A NAME="pmiconwindow"></A><LI>It's inconvenient to extend the Window abstraction to cover differentkinds of windows or new platforms. Imagine an IconWindow subclass ofWindow that specializes the Window abstraction for icons.  To supportIconWindows for both platforms, we have to implement <EM>two</EM> newclasses, XIconWindow and PMIconWindow. Worse, we'll have to define twoclasses for <EM>every</EM> kind of window. Supporting a third platformrequires yet another new Window subclass for every kind of window.<A NAME="pmiconwindow-151c"></A><A NAME="pmwindow-151c"></A><A NAME="151c"></A><P ALIGN=CENTER><IMG SRC="Pictures/bridg098.gif"></LI><A NAME="auto1003"></A><P></P><A NAME="auto1004"></A><LI>It makes client code platform-dependent. Whenever a client creates awindow, it instantiates a concrete class that has a specificimplementation. For example, creating an XWindow object binds theWindow abstraction to the X Window implementation, which makes theclient code dependent on the X Window implementation.  This, in turn,makes it harder to port the client code to other platforms.<A NAME="auto1005"></A><P>Clients should be able to create a window without committing to aconcrete implementation. Only the window implementation should dependon the platform on which the application runs. Therefore client codeshould instantiate windows without mentioning specific platforms.</LI></OL><A NAME="pmwindowimp"></A><A NAME="window"></A><A NAME="xwindowimp"></A><P>The Bridge pattern addresses these problems by putting the Windowabstraction and its implementation in separate class hierarchies.There is one class hierarchy for window interfaces (Window,IconWindow, TransientWindow) and a separate hierarchy forplatform-specific window implementations, with WindowImp as its root.The XWindowImp subclass, for example, provides an implementation basedon the X Window System.</P><A NAME="pmwindowimp-152c"></A><A NAME="152c"></A><P ALIGN=CENTER><IMG SRC="Pictures/bridg100.gif"></P><A NAME="windowimp"></A><P>All operations on Window subclasses are implemented in terms of abstractoperations from the WindowImp interface. This decouples the windowabstractions from the various platform-specific implementations. Werefer to the relationship between Window and WindowImp as a<STRONG>bridge</STRONG>, because it bridges the abstraction and itsimplementation, letting them vary independently.</P><A NAME="applicability"></A><H2><A HREF="#structure"><IMG SRC="gifsb/down3.gif" BORDER=0 ALT="next: Structure"></A> Applicability</H2> <A NAME="auto1006"></A><P>Use the Bridge pattern when</P><UL><A NAME="auto1007"></A><LI>you want to avoid a permanent binding between an abstraction and itsimplementation. This might be the case, for example, when theimplementation must be selected or switched at run-time.</LI><A NAME="auto1008"></A><P></P><A NAME="auto1009"></A><LI>both the abstractions and their implementations should be extensibleby subclassing. In this case, the Bridge pattern lets you combine thedifferent abstractions and implementations and extend themindependently.</LI><A NAME="auto1010"></A><P></P><A NAME="auto1011"></A><LI>changes in the implementation of an abstraction should have no impacton clients; that is, their code should not have to be recompiled.</LI><A NAME="auto1012"></A><P></P><A NAME="auto1013"></A><LI>(C++) you want to hide the implementation of an abstraction completelyfrom clients. In C++ the representation of a class is visible in theclass interface.</LI><A NAME="auto1014"></A><P></P><A NAME="auto1015"></A><LI>you have a proliferation of classes as shown earlier in the first Motivationdiagram.  Such a class hierarchy indicates the need for splitting anobject into two parts. Rumbaugh uses the term "nestedgeneralizations" [<A HREF="bibfs.htm#rumbaugh_omt" TARGET="_mainDisplayFrame">RBP+91</A>] to refer to such classhierarchies.</LI><A NAME="auto1016"></A><P></P><A NAME="auto1017"></A><LI>you want to share an implementation among multiple objects (perhapsusing reference counting), and this fact should be hidden from theclient.  A simple example is Coplien's Stringclass [<A HREF="bibfs.htm#coplien_idioms" TARGET="_mainDisplayFrame">Cop92</A>], in which multiple objects can share thesame string representation (StringRep).</LI></UL><A NAME="structure"></A><H2><A HREF="#participants"><IMG SRC="gifsb/down3.gif" BORDER=0 ALT="next: Participants"></A> Structure</H2> <P ALIGN=CENTER><IMG SRC="Pictures/bridge.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="auto1018"></A><LI><B>Abstraction</B> (Window)<A NAME="auto1019"></A><P></P>    <UL>    <A NAME="auto1020"></A><LI>defines the abstraction's interface.</LI>    <A NAME="auto1021"></A><P><!-- extra space --></P>    <A NAME="auto1022"></A><LI>maintains a reference to an object of type Implementor.</LI>    </UL><A NAME="auto1023"></A><P></P><A NAME="refinedabs-part-bridge"></A><LI><B>RefinedAbstraction</B> (IconWindow)<A NAME="auto1024"></A><P></P>    <UL>    <A NAME="auto1025"></A><LI>Extends the interface defined by Abstraction.</LI>    </UL><A NAME="auto1026"></A><P></P><A NAME="auto1027"></A><LI><B>Implementor</B> (WindowImp)<A NAME="auto1028"></A><P></P>    <UL>    <A NAME="auto1029"></A><LI>defines the interface for implementation classes.  This	interface doesn't have to correspond exactly to Abstraction's	interface; in fact the two interfaces can be quite different.	Typically the Implementor interface provides only primitive	operations, and Abstraction defines higher-level	operations based on these primitives.    </UL><A NAME="auto1030"></A><P></P><A NAME="auto1031"></A><LI><B>ConcreteImplementor</B> (XWindowImp, PMWindowImp)<A NAME="auto1032"></A><P></P>    <UL>    <A NAME="auto1033"></A><LI>implements the Implementor interface and defines its        concrete implementation.    </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="auto1034"></A><LI>Abstraction forwards client requests to its Implementor object.</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="auto1035"></A><P>The Bridge pattern has the following consequences:</P><OL><A NAME="decouple-iandi"><A NAME="auto1036"></A><LI><EM>Decoupling interface and implementation.</EM>An implementation is not bound permanently to an interface. Theimplementation of an abstraction can be configured at run-time.It's even possible for an object to change its implementationat run-time.<A NAME="auto1037"></A><P>Decoupling Abstraction and Implementor also eliminates compile-timedependencies on the implementation. Changing an implementation classdoesn't require recompiling the Abstraction class and itsclients. This property is essential when you must ensure binarycompatibility between different versions of a class library.</P><A NAME="auto1038"></A><P>Furthermore, this decoupling encourages layering that can lead to abetter-structured system. The high-level part of a system only has toknow about Abstraction and Implementor.</P></LI><A NAME="auto1039"></A><P></P><A NAME="auto1040"></A><LI><EM>Improved extensibility.</EM>You can extend the Abstraction and Implementor hierarchies independently.</LI><A NAME="auto1041"></A><P></P><A NAME="auto1042"></A><LI><EM>Hiding implementation details from clients.</EM>You can shield clients from implementation details, like the sharingof implementor objects and the accompanying reference count mechanism(if any).</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="auto1043"></A><P>Consider the following implementation issues when applying the Bridgepattern:</P><OL><A NAME="auto1044"></A><LI><EM>Only one Implementor.</EM>In situations where there's only one implementation, creating anabstract Implementor class isn't necessary. This is a degenerate caseof the Bridge pattern; there's a one-to-one relationship betweenAbstraction and Implementor. Nevertheless, this separation is stilluseful when a change in the implementation of a class must not affectits existing clients&#151;that is, they shouldn't have to be recompiled,just relinked.<A NAME="auto1045"></A><P>Carolan [<A HREF="bibfs.htm#carolan_bullet-proof" TARGET="_mainDisplayFrame">Car89</A>] uses the term "Cheshire Cat" todescribe this separation.  In C++, the class interface of theImplementor class can be defined in a private header file that isn'tprovided to clients.  This lets you hide an implementation of a classcompletely from its clients.</P></LI><A NAME="auto1046"></A><P></P><A NAME="auto1047"></A><LI><EM>Creating the right Implementor object.</EM>How, when, and where do you decide which Implementor class toinstantiate when there's more than one?<A NAME="auto1048"></A><P>If Abstraction knows about all ConcreteImplementor classes, then itcan instantiate one of them in its constructor; it can decide betweenthem based on parameters passed to its constructor.  If, for example,a collection class supports multiple implementations, the decision canbe based on the size of the collection. A linked list implementationcan be used for small collections and a hash table for larger ones.</P><A NAME="auto1049"></A><P>Another approach is to choose a default implementation initially andchange it later according to usage.  For example, if the collectiongrows bigger than a certain threshold, then it switches itsimplementation to one that's more appropriate for a large number ofitems.</P><A NAME="auto1050"></A><P>It's also possible to delegate the decision to another objectaltogether.  In the Window/WindowImp example, we can introduce afactory object (see <A HREF="pat3afs.htm" TARGET="_mainDisplayFrame">Abstract Factory (87)</A>)whose sole duty is to encapsulate platform-specifics.  The factoryknows what kind of WindowImp object to create for the platform in use;a Window simply asks it for a WindowImp, and it returns the rightkind.  A benefit of this approach is that Abstraction is not coupleddirectly to any of the Implementor classes.</P></LI><A NAME="auto1051"></A><P></P><A NAME="auto1052"></A><LI><EM>Sharing implementors.</EM>Coplien illustrates how the Handle/Body idiom in C++ can be used toshare implementations among several objects [<A HREF="bibfs.htm#coplien_idioms" TARGET="_mainDisplayFrame">Cop92</A>]. TheBody stores a reference count that the Handle class increments anddecrements. The code for assigning handles with shared bodies has thefollowing general form:<A NAME="auto1053"></A><PRE>

⌨️ 快捷键说明

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