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

📄 chap2.htm

📁 设计模式英文版 作者:Erich Gamma、Richard Helm、Ralph Johnson和John Vlissides 四人帮的书。 学设计模式的必读的书籍!经典中的经典
💻 HTM
📖 第 1 页 / 共 5 页
字号:
<PRE>
    GUIFactory* guiFactory;
    const char* styleName = getenv("LOOK_AND_FEEL");
        // user or environment supplies this at startup
    
    if (strcmp(styleName, "Motif") == 0) {
        guiFactory = new MotifFactory;
    
    } else if (strcmp(styleName, "Presentation_Manager") == 0) {
        guiFactory = new PMFactory;
    
    } else {
        guiFactory = new DefaultGUIFactory;
    }
</PRE>

<A NAME="auto1083"></A>
<P>There are more sophisticated ways to select the factory at run-time.
For example, you could maintain a registry that maps strings to
factory objects.  That lets you register instances of new factory
subclasses without modifying existing code, as the preceding approach 
requires.  And you don't have to link all platform-specific factories
into the application.  That's important, because it might not be
possible to link a MotifFactory on a platform that doesn't support
Motif.</P>

<A NAME="auto1084"></A>
<P>But the point is that once we've configured the application with the
right factory object, its look and feel is set from then on.  If we
change our minds, we can reinitialize <CODE>guiFactory</CODE> with a
factory for a different look and feel and then reconstruct the
interface.  Regardless of how and when we decide to initialize
<CODE>guiFactory</CODE>, we know that once we do, the application can
create the appropriate look and feel without modification.</P>

<A NAME="absfact"></A>
<H3>Abstract Factory Pattern</H3>

<A NAME="auto1085"></A>
<P>Factories and products are the key participants in the <A HREF="pat3afs.htm" TARGET="_mainDisplayFrame">Abstract Factory&nbsp;(87)</A> pattern. This pattern captures how
to create families of related product objects without instantiating
classes directly.  It's most appropriate when the number and general
kinds of product objects stay constant, and there are differences in
specific product families. We choose between families by instantiating
a particular concrete factory and using it consistently to create
products thereafter. We can also swap entire families of products by
replacing the concrete factory with an instance of a different one.
The Abstract Factory pattern's emphasis on <EM>families</EM> of products
distinguishes it from other creational patterns, which involve only one
kind of product object.</P>

<A NAME="sec2-6"></A>
<H2><A HREF="#sec2-7"><IMG SRC="gifsb/down3.gif" BORDER=0></A>
Supporting Multiple Window Systems</H2>

<A NAME="auto1086"></A>
<P>Look and feel is just one of many portability issues. Another is the
windowing environment in which Lexi runs. A platform's window system
creates the illusion of multiple overlapping windows on a bitmapped
display. It manages screen space for windows and routes input to them from
the keyboard and mouse. Several important and largely incompatible window
systems exist today (e.g., Macintosh, Presentation Manager, Windows, X).
We'd like Lexi to run on as many of them as possible for exactly the
same reasons we support multiple look-and-feel standards.</P>

<H3>Can We Use an Abstract Factory?</H3>

<A NAME="auto1087"></A>
<P>At first glance this may look like another opportunity to apply the
Abstract Factory pattern. But the constraints for window system portability
differ significantly from those for look-and-feel independence.

<A NAME="auto1088"></A>
<P>In applying the Abstract Factory pattern, we assumed we would define
the concrete widget glyph classes for each look-and-feel standard.
That meant we could derive each concrete product for a particular
standard (e.g., MotifScrollBar and MacScrollBar) from an abstract
product class (e.g., ScrollBar). But suppose we already have several
class hierarchies from different vendors, one for each look-and-feel
standard.  Of course, it's highly unlikely these hierarchies are
compatible in any way.  Hence we won't have a common abstract product
class for each kind of widget (ScrollBar, Button, Menu, etc.)---and the
Abstract Factory pattern won't work without those crucial classes.
We have to make the different widget hierarchies adhere to a common
set of abstract product interfaces.  Only then could we declare the
<CODE>Create...</CODE> operations properly in our abstract factory's
interface.</P>

<A NAME="auto1089"></A>
<P>We solved this problem for widgets by developing our own abstract and
concrete product classes.  Now we're faced with a similar problem when
we try to make Lexi work on existing window systems; namely,
different window systems have incompatible programming interfaces.
Things are a bit tougher this time, though, because we can't afford to
implement our own nonstandard window system.</P>

<A NAME="auto1090"></A>
<P>But there's a saving grace. Like look-and-feel standards, window
system interfaces aren't radically different from one another, because
all window systems do generally the same thing.  We need a uniform set
of windowing abstractions that lets us take different window system
implementations and slide any one of them under a common interface.</P>

<H3>Encapsulating Implementation Dependencies</H3>

<A NAME="auto1091"></A>
<P>In <A HREF="#editor_sec_document_structure">Section&nbsp;2.2</A>
we introduced a Window class for displaying a glyph or glyph
structure on the display.  We didn't specify the window system that
this object worked with, because the truth is that it doesn't come
from any particular window system. The Window class encapsulates
the things windows tend to do across window systems:</P>

<UL>

<A NAME="auto1092"></A>
<LI>They provide operations for drawing basic geometric shapes.</LI>

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

<A NAME="auto1094"></A>
<LI>They can iconify and de-iconify themselves.</LI>

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

<A NAME="auto1096"></A>
<LI>They can resize themselves.</LI>

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

<A NAME="auto1098"></A>
<LI>They can (re)draw their contents on demand, for example, when they
are de-iconified or when an overlapped and obscured portion of their
screen space is exposed.</LI>

</UL>

<A NAME="auto1099"></A>
<P>The Window class must span the functionality of windows from different
window systems. Let's consider two extreme philosophies:</P>

<OL>

<A NAME="auto1100"></A>
<LI><EM>Intersection of functionality.</EM>
The Window class interface provides only functionality that's common
to <EM>all</EM> window systems.  The problem with this approach is that
our Window interface winds up being only as powerful as the least
capable window system. We can't take advantage of more advanced
features even if most (but not all) window systems support them.</LI>

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

<A NAME="auto1102"></A>
<LI><EM>Union of functionality.</EM>
Create an interface that incorporates the capabilities of <EM>all</EM>
existing systems. The trouble here is that the resulting interface may
well be huge and incoherent.  Besides, we'll have to change it (and
Lexi, which depends on it) anytime a vendor revises its window
system interface.</LI>

</OL>

<A NAME="auto1103"></A>
<P>Neither extreme is a viable solution, so our design will fall
somewhere between the two.  The Window class will provide a convenient
interface that supports the most popular windowing features. Because
Lexi will deal with this class directly, the Window class must also
support the things Lexi knows about, namely, glyphs.  That means
Window's interface must include a basic set of graphics operations
that lets glyphs draw themselves in the window.
<A HREF="#editor_window_base_class_interface">Table&nbsp;2.3</A>
gives a sampling of the operations in the Window class interface.</P>

<CENTER>
<TABLE	
	BORDER		= 1
	CELLPADDING	= 4
	CELLSPACING	= 0
	BGCOLOR		= #99CCFF
>

<A NAME="editor_window_base_class_interface"></A>
<TR>
<TH BGCOLOR=#6699CC>Responsibility</TH>
<TH BGCOLOR=#6699CC>Operations</TH>
</TR>

<A NAME="auto1104"></A>
<TR>
<TD VALIGN=TOP>window management</TD>
<TD><CODE>virtual void Redraw()</CODE><BR>
<CODE>virtual void Raise()</CODE><BR>
<CODE>virtual void Lower()</CODE><BR>
<CODE>virtual void Iconify()</CODE><BR>
<CODE>virtual void Deiconify()</CODE><BR>
<CODE>...</CODE></TD>
</TR>

<A NAME="auto1105"></A>
<TR>
<TD VALIGN=TOP>graphics</TD>
<TD><CODE>virtual void DrawLine(...)</CODE><BR>
<CODE>virtual void DrawRect(...)</CODE><BR>
<CODE>virtual void DrawPolygon(...)</CODE><BR>
<CODE>virtual void DrawText(...)</CODE><BR>
<CODE>...</CODE></TD>
</TR>

</TABLE>
</CENTER>

<P ALIGN=CENTER>Table 2.3:&nbsp;&nbsp;Window class interface</P>

<A NAME="appwin"></A>
<P>Window is an abstract class. Concrete subclasses of Window support the
different kinds of windows that users deal with. For example,
application windows, icons, and warning dialogs are all windows, but
they have somewhat different behaviors. So we can define subclasses
like ApplicationWindow, IconWindow, and DialogWindow to capture these
differences. The resulting class hierarchy gives applications like
Lexi a uniform and intuitive windowing abstraction, one that doesn't
depend on any particular vendor's window system:</P>

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

<A NAME="auto1106"></A>
<P>Now that we've defined a window interface for Lexi to work with,
where does the real platform-specific window come in? If we're not
implementing our own window system, then at some point our window
abstraction must be implemented in terms of what the target window
system provides. So where does that implementation live?</P>

<A NAME="auto1107"></A>
<P>One approach is to implement multiple versions of the Window class and
its subclasses, one version for each windowing platform. We'd have to
choose the version to use when we build Lexi for a given platform.
But imagine the maintenance headaches we'd have keeping track of
multiple classes, all named "Window" but each implemented on a
different window system.  Alternatively, we could create
implementation-specific subclasses of each class in the Window
hierarchy&#151;and end up with another subclass explosion problem like the one
we had trying to add embellishments.  Both of these alternatives have
another drawback: Neither gives us the flexibility to change the
window system we use after we've compiled the program. So we'll have
to keep several different executables around as well.</P>

<A NAME="encap-var-concept"></A>
<P>Neither alternative is very appealing, but what else can we do? The
same thing we did for formatting and embellishment, namely, <EM>encapsulate the concept that varies</EM>. What varies in this case is the
window system implementation. If we encapsulate a window system's
functionality in an object, then we can implement our Window class and
subclasses in terms of that object's interface. Moreover, if that
interface can serve all the window systems we're interested in, then
we won't have to change Window or any of its subclasses to support
different window systems. We can configure window objects to the
window system we want simply by passing them the right window
system-encapsulating object. We can even configure the window at
run-time.</P>

<A NAME="windowimp"></A>
<A NAME="windowimp-subclass"></A>
<H3>Window and WindowImp</H3>

<A NAME="auto1108"></A>
<P>We'll define a separate <STRONG>WindowImp</STRONG> class hierarchy in which to
hide different window system implementations. WindowImp is an abstract
class for objects that encapsulate window system-dependent code. To make
Lexi work on a particular window system, we configure each window
object with an instance of a WindowImp subclass for that system.  The
following diagram shows the relationship between the Window and WindowImp
hierarchies:</P>

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

<A NAME="auto1109"></A>
<P>By hiding the implementations in WindowImp classes, we avoid polluting
the Window classes with window system dependencies, which keeps the
Window class hierarchy comparatively small and stable. Meanwhile we
can easily extend the implementation hierarchy to support new window
systems.</P>

<H3>WindowImp Subclasses</H3>

<A NAME="auto1110"></A>
<P>Subclasses of WindowImp convert requests into window system-specific
operations. Consider the example we used in
<A HREF="#sec2-2">Section&nbsp;2.2</A>. We defined the
<CODE>Rectangle::Draw</CODE> in terms of the <CODE>DrawRect</CODE> operation on
the Window instance:</P>

<A NAME="auto1111"></A>
<PRE>
    void Rectangle::Draw (Window* w) {
        w->DrawRect(_x0, _y0, _x1, _y1);
    }

⌨️ 快捷键说明

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