📄 chap2.htm
字号:
<HTML><HEAD><TITLE>A Case Study: Designing a Document Editor</TITLE><SCRIPT>function setFocus() { if ((navigator.appName != "Netscape") && (parseFloat(navigator.appVersion) == 2)) { return; } else { self.focus(); }}</SCRIPT></HEAD><BODY BGCOLOR="#FFFFFF" onLoad="setFocus()";><A NAME="top"></A><A NAME="chapter_scenario"></A><P>This chapter presents a case study in the design of a"What-You-See-Is-What-You-Get" (or "WYSIWYG") document editor called<STRONG>Lexi</STRONG>.<A NAME="fn1"></A><A HREF="#footnote1"><SUP>1</SUP></A> We'llsee how design patterns capture solutions to design problems inLexi and applications like it. By the end of this chapter you willhave gained experience with eight patterns, learning them byexample.</P><A NAME="lexi-userint"></A><P><A HREF="#editor_Lexi">Figure 2.1</A> depicts Lexi's user interface. AWYSIWYG representation of the document occupies the large rectangulararea in the center. The document can mix text and graphics freely ina variety of formatting styles. Surrounding the document are theusual pull-down menus and scroll bars, plus a collection of page iconsfor jumping to a particular page in the document.</P><A NAME="editor_Lexi"></A><P ALIGN=CENTER><IMG SRC="Pictures/doc.gif"><BR><BR>Figure 2.1: Lexi's user interface</P><A NAME="sec2-1"></A><H2><A HREF="#sec2-2"><IMG SRC="gifsb/down3.gif" BORDER=0 ALT="next: Document Structure"></A>Design Problems</H2><A NAME="auto1000"></A><P>We will examine seven problems in Lexi's design:</P><OL><A NAME="auto1001"></A><LI><EM>Document structure.</EM>The choice of internal representation for the document affects nearlyevery aspect of Lexi's design. All editing, formatting, displaying,and textual analysis will require traversing the representation. Theway we organize this information will impact the design of the rest ofthe application.</LI><A NAME="auto1002"></A><P></P><A NAME="auto1003"></A><LI><EM>Formatting.</EM>How does Lexi actually arrange text and graphics into lines andcolumns? What objects are responsible for carrying out differentformatting policies? How do these policies interact with thedocument's internal representation?</LI><A NAME="auto1004"></A><P></P><A NAME="auto1005"></A><LI><EM>Embellishing the user interface.</EM>Lexi's user interface includes scroll bars, borders, and drop shadowsthat embellish the WYSIWYG document interface. Such embellishments arelikely to change as Lexi's user interface evolves. Hence it'simportant to be able to add and remove embellishments easily withoutaffecting the rest of the application.</LI><A NAME="auto1006"></A><P></P><A NAME="lexi-looknfeel"></A><A NAME="present-manage"></A><LI><EM>Supporting multiple look-and-feel standards.</EM>Lexi should adapt easily to different look-and-feel standardssuch as Motif and Presentation Manager (PM) without major modification.</LI><A NAME="auto1007"></A><P></P><A NAME="multiple-windows"></A><LI><EM>Supporting multiple window systems.</EM>Different look-and-feel standards are usually implemented on differentwindow systems. Lexi's design should be as independent of the windowsystem as possible.</LI><A NAME="auto1008"></A><P></P><A NAME="auto1009"></A><LI><EM>User operations.</EM>Users control Lexi through various user interfaces, includingbuttons and pull-down menus. The functionality behind theseinterfaces is scattered throughout the objects in the application.The challenge here is to provide a uniform mechanism both foraccessing this scattered functionality and for undoing its effects.</LI><A NAME="auto1010"></A><P></P><A NAME="auto1011"></A><LI><EM>Spelling checking and hyphenation.</EM>How does Lexi support analytical operations such as checking formisspelled words and determining hyphenation points? How can weminimize the number of classes we have to modify to add a newanalytical operation?</LI></OL><A NAME="auto1012"></A><P>We discuss these design problems in the sections that follow. Eachproblem has an associated set of goals plus constraints on how weachieve those goals. We explain the goals and constraints in detailbefore proposing a specific solution. The problem and its solutionwill illustrate one or more design patterns. The discussion for eachproblem will culminate in a brief introduction to the relevantpatterns.</P><A NAME="sec2-2"></A><H2><A HREF="#sec2-3"><IMG SRC="gifsb/down3.gif" BORDER=0 ALT="next: Formatting"></A>Document Structure</H2><A NAME="editor_sec_document_structure"></A><P>A document is ultimately just an arrangement of basic graphicalelements such as characters, lines, polygons, and other shapes. Theseelements capture the total information content of the document. Yet anauthor often views these elements not in graphical terms but in termsof the document's physical structure—lines, columns, figures,tables, and other substructures.<A NAME="fn2"></A><A HREF="#footnote2"><SUP>2</SUP></A>In turn, these substructures have substructures of theirown, and so on.</P><A NAME="auto1013"></A><P>Lexi's user interface should let users manipulate thesesubstructures directly. For example, a user should be able to treat adiagram as a unit rather than as a collection of individual graphicalprimitives. The user should be able to refer to a table as a whole,not as an unstructured mass of text and graphics. That helps make theinterface simple and intuitive. To give Lexi's implementationsimilar qualities, we'll choose an internal representation thatmatches the document's physical structure.</P><A NAME="auto1014"></A><P>In particular, the internal representation should support thefollowing:</P><UL><A NAME="auto1015"></A><LI>Maintaining the document's physical structure, that is, thearrangement of text and graphics into lines, columns, tables, etc.</LI><A NAME="auto1016"></A><P></P><A NAME="auto1017"></A><LI>Generating and presenting the document visually.</LI><A NAME="auto1018"></A><P></P><A NAME="auto1019"></A><LI>Mapping positions on the display to elements in the internalrepresentation. This lets Lexi determine what the user isreferring to when he points to something in the visual representation.</LI></UL><A NAME="auto1020"></A><P>In addition to these goals are some constraints. First, we shouldtreat text and graphics uniformly. The application's interface letsthe user embed text within graphics freely and vice versa. We shouldavoid treating graphics as a special case of text or text as a specialcase of graphics; otherwise we'll end up with redundant formatting andmanipulation mechanisms. One set of mechanisms should suffice forboth text and graphics.</P><A NAME="auto1021"></A><P>Second, our implementation shouldn't have to distinguish betweensingle elements and groups of elements in the internal representation.Lexi should be able to treat simple and complex elementsuniformly, thereby allowing arbitrarily complex documents. The tenthelement in line five of column two, for instance, could be a singlecharacter or an intricate diagram with many subelements. As long as weknow this element can draw itself and specify its dimensions, itscomplexity has no bearing on how and where it should appear on thepage.</P><A NAME="auto1022"></A><P>Opposing the second constraint, however, is the need to analyze thetext for such things as spelling errors and potential hyphenationpoints. Often we don't care whether the element of a line is a simpleor complex object. But sometimes an analysis depends on the objectsbeing analyzed. It makes little sense, for example, to check thespelling of a polygon or to hyphenate it. The internalrepresentation's design should take this and other potentiallyconflicting constraints into account.</P><A NAME="recursivecomposition"></A><H3>Recursive Composition</H3><A NAME="auto1023"></A><P>A common way to represent hierarchically structured information isthrough a technique called <STRONG>recursive composition</STRONG>, whichentails building increasingly complex elements out of simpler ones.Recursive composition gives us a way to compose a document out ofsimple graphical elements. As a first step, we can tile a set ofcharacters and graphics from left to right to form a line in thedocument. Then multiple lines can be arranged to form a column,multiple columns can form a page, and so on (see<A HREF="#editor_recursive_composition">Figure 2.2</A>).<A NAME="editor_recursive_composition"></A><P ALIGN=CENTER><IMG SRC="Pictures/textcomp.gif"><BR><BR>Figure 2.2: Recursive composition of text and graphics</P><A NAME="auto1024"></A><P>We can represent this physical structure by devoting an object to eachimportant element. That includes not just the visible elements likethe characters and graphics but the invisible, structural elements aswell—the lines and the column. The result is the object structureshown in <A HREF="#editor_object_structure">Figure 2.3</A>.</P><A NAME="editor_object_structure"></A><P ALIGN=CENTER><IMG SRC="Pictures/texts008.gif"><BR><BR>Figure 2.3: Object structure for recursive composition oftext and graphics</P><A NAME="auto1025"></A><P>By using an object for each character and graphical element in thedocument, we promote flexibility at the finest levels of Lexi'sdesign. We can treat text and graphics uniformly with respect to howthey are drawn, formatted, and embedded within each other. We canextend Lexi to support new character sets without disturbing otherfunctionality. Lexi's object structure mimics the document'sphysical structure.</P><A NAME="auto1026"></A><P>This approach has two important implications. The first is obvious:The objects need corresponding classes. The second implication, whichmay be less obvious, is that these classes must have compatibleinterfaces, because we want to treat the objects uniformly. The way tomake interfaces compatible in a language like C++ is to relate theclasses through inheritance.</P><A NAME="section_glyphs"></A><H3>Glyphs</H3><A NAME="auto1027"></A><P>We'll define a <STRONG>Glyph</STRONG> abstract class for allobjects that can appear in a document structure.<A NAME="fn3"></A><AHREF="#footnote3"><SUP>3</SUP></A> Its subclasses define bothprimitive graphical elements (like characters and images) andstructural elements (like rows and columns). <A HREF="#editor_glyph_class_hierarchy">Figure 2.4</A> depicts a representative partof the Glyph class hierarchy, and <A HREF="#editor_basic_glyph_interface">Table 2.1</A> presents the basic glyph interfacein more detail using C++ notation.<A NAME="fn4"></A><A HREF="#footnote4"><SUP>4</SUP></A></P><A NAME="editor_glyph_class_hierarchy"></A><P ALIGN=CENTER><IMG SRC="Pictures/glyph046.gif"><BR><BR>Figure 2.4: Partial Glyph class hierarchy</P><A NAME="editor_basic_glyph_interface"></A><CENTER><TABLE CELLPADDING = 4 BORDER = 1 CELLSPACING = 0 BGCOLOR = #99CCFF><A NAME="auto1028"></A><TR><TH BGCOLOR=#6699CC ALIGN=CENTER>Responsibility</TH><TH BGCOLOR=#6699CC ALIGN=CENTER>Operations</TH></TR><TR VALIGN=TOP><TD ALIGN=CENTER>appearance</TD><TD ALIGN=LEFT><CODE>virtual void Draw(Window*)</CODE><BR><CODE>virtual void Bounds(Rect&)</CODE></TD></TR> <TR VALIGN=TOP><TD ALIGN=CENTER>hit detection</TD><TD ALIGN=LEFT><CODE>virtual bool Intersects(const Point&)</CODE></TD></TR><TR VALIGN=TOP><TD ALIGN=CENTER>structure</TD><TD ALIGN=LEFT><CODE>virtual void Insert(Glyph*, int)</CODE><BR><CODE>virtual void Remove(Glyph*)</CODE><BR><CODE>virtual Glyph* Child(int)</CODE><BR><CODE>virtual Glyph* Parent()</CODE></TD></TR></TABLE></CENTER><P ALIGN=CENTER>Table 2.1: Basic glyph interface</P><A NAME="auto1029"></A><P>Glyphs have three basic responsibilities. They know (1) how to draw
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -