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

📄 ch18.htm

📁 一本好的VC学习书,本人就是使用这本书开始学习的vc,希望能对大家有帮助
💻 HTM
📖 第 1 页 / 共 5 页
字号:
however, you have to think long and hard about what you are trying to accomplishto find the right objects.</P><P>Don't despair. Most designs are not perfect the first time. A good starting pointis to describe the problem out loud. Make a list of all the nouns and verbs you usewhen describing the project. The nouns are good candidates for objects. The verbsmight be the methods of those objects (or they may be objects in their own right).This is not a foolproof method, but it is a good technique to use when getting startedon your design.</P><P>That was the easy part. Now the question arises, &quot;Should the message headerbe a separate class from the body?&quot; If so, do you need parallel hierarchies,<TT>CompuServeBody</TT> and <TT>CompuServeHeader</TT>, as well as <TT>ProdigyBody</TT>and <TT>ProdigyHeader</TT>?</P><P>Parallel hierarchies are often a warning sign of a bad design. It is a commonerror in object-oriented design to have a set of objects in one hierarchy, and amatching set of &quot;managers&quot; of those objects in another. The burden of keepingthese hierarchies up-to-date and in sync with each other soon becomes overwhelming:a classic maintenance nightmare.</P><P>There are no hard-and-fast rules, of course, and at times such parallel hierarchiesare the most efficient way to solve a particular problem. Nonetheless, if you seeyour design moving in this direction, you should rethink the problem; there may bea more elegant solution available.</P><P>When the messages arrive from the e-mail provider, they will not necessarily beseparated into header and body; many will be one large stream of data, which yourprogram will have to disentangle. Perhaps your hierarchy should reflect that ideadirectly.</P><P>Further reflection on the tasks at hand leads you to try to list the propertiesof these messages, with an eye towards introducing capabilities and data storageat the right level of abstraction. Listing properties of your objects is a good wayto find the data members, as well as to &quot;shake out&quot; other objects you mightneed.</P><P>Mail messages will need to be stored, as will the user's preferences, phone numbers,and so forth. Storage clearly needs to be high up in the hierarchy. Should the mailmessages necessarily share a base class with the preferences?<H3 ALIGN="CENTER"><A NAME="Heading18"></A><FONT COLOR="#000077">Rooted HierarchiesVersus Non-Rooted Hierarchies</FONT></H3><P>There are two overall approaches to inheritance hierarchies: you can have all,or nearly all, of your classes descend from a common root class, or you can havemore than one inheritance hierarchy. An advantage of a common root class is thatyou often can avoid multiple inheritance; a disadvantage is that many times implementationwill percolate up into the base class.</P><DL>	<DD><HR><FONT COLOR="#000077"><B>New Term: </B></FONT>A set of classes is <I>rooted</I> if	all share a common ancestor. <I>Non-rooted</I> hierarchies do not all share a common	base class. <HR></DL><P>Because you know that your product will be developed on many platforms, and becausemultiple inheritance is complex and not necessarily well supported by all compilerson all platforms, your first decision is to use a rooted hierarchy and single inheritance.You decide to identify those places where multiple inheritance might be used in thefuture, and to design so that breaking apart the hierarchy and adding multiple inheritanceat a later time need not be traumatic to your entire design.</P><P>You decide to prefix the name of all of your internal classes with the letter<TT>p</TT> so that you can easily and quickly tell which classes are yours and whichare from other libraries. On Day 21, &quot;What's Next,&quot; you'll learn aboutname spaces, which can reinforce this idea, but for now the initial will do nicely.</P><P>Your root class will be <TT>pObject</TT>; virtually every class you create willdescend from this object. <TT>pObject</TT> itself will be kept fairly simple; onlythat data which absolutely every item shares will appear in this class.</P><P>If you want a rooted hierarchy, you'll want to give the root class a fairly genericname (like <TT>pObject</TT>) and few capabilities. The point of a root object isto be able to create collections of all its descendants and refer to them as instancesof <TT>pObject</TT>. The trade-off is that rooted hierarchies often percolate interfaceup into the root class. You will pay the price; by percolating these interfaces upinto the root object, other descendants will have interfaces that are inappropriateto their design. The only good solution to this problem, in single inheritance, isto use templates. Templates are discussed tomorrow.</P><P>The next likely candidates for top of the hierarchy status are <TT>pStored</TT>and <TT>pWired</TT>. <TT>pStored</TT> objects are saved to disk at various times(for example when the program is not in use), and <TT>pWired</TT> objects are sentover the modem or network. Because nearly all of your objects will need to be storedto disk, it makes sense to push this functionality up high in the hierarchy. Becauseall the objects that are sent over the modem must be stored, but not all stored objectsmust be sent over the wire, it makes sense to derive <TT>pWired</TT> from <TT>pStored</TT>.</P><P>Each derived class acquires all the knowledge (data) and functionality (methods)of its base class, and each should add one discrete additional ability. Thus, <TT>pWired</TT>may add various methods, but all are in service of adding the ability to be transferredover the modem.</P><P>It is possible that all wired objects are stored, or that all stored objects arewired, or that neither of these statements is true. If only some wired objects arestored, and only some stored objects are wired, you will be forced either to usemultiple inheritance or to &quot;hack around&quot; the problem. A potential &quot;hack&quot;for such a situation would be to inherit, for example, <TT>Wired</TT> from <TT>Stored</TT>,and then for those objects that are sent via modem, but are never stored, to makethe stored methods do nothing or return an error.</P><P>In fact, you realize that some stored objects clearly are not wired: for example,user preferences. All wired objects, however, are stored, and so your inheritancehierarchy so far is as reflected in Figure 18.1.<BR><BR><A NAME="Heading19"></A><A HREF="18zcp01.jpg" tppabs="http://www.mcp.com/814147200/0-672/0-672-31070-8/art/ch18/18zcp01.jpg"><FONT COLOR="#000077">Figure18.1.</FONT></A><FONT COLOR="#000077"> </FONT><I>Initial inheritance hierarchy.</I><H3 ALIGN="CENTER"><A NAME="Heading20"></A><FONT COLOR="#000077">Designing the Interfaces</FONT></H3><P>It is important at this stage of designing your product to avoid being concernedwith implementation. You want to focus all of your energies on designing a cleaninterface among the classes and then delineating what data and methods each classwill need.</P><P>It is often a good idea to have a solid understanding of the base classes beforetrying to design the more derived classes, so you decide to focus on <TT>pObject</TT>,<TT>pStored</TT>, and <TT>pWired</TT>.</P><P>The root class, <TT>pObject</TT>, will only have the data and methods that arecommon to everything on your system. Perhaps every object should have a unique identificationnumber. You could create <TT>pID</TT> (PostMaster ID) and make that a member of <TT>pObject</TT>;but first you must ask yourself, &quot;Does any object that is not stored and notwired need such a number?&quot; That begs the question, &quot;Are there any objectsthat are not stored, but that are part of this hierarchy?&quot;</P><P>If there are no such objects, you may want to consider collapsing <TT>pObject</TT>and <TT>pStored</TT> into one class; after all, if all objects are stored, what isthe point of the differentiation? Thinking this through, you realize that there maybe some objects, such as address objects, that it would be beneficial to derive from<TT>pObject</TT>, but that will never be stored on their own; if they are stored,they will be as part of some other object.</P><P>That says that for now having a separate <TT>pObject</TT> class would be useful.One can imagine that there will be an address book that would be a collection of<TT>pAddress</TT> objects, and while no <TT>pAddress</TT> will ever be stored onits own, there would be utility in having each one have its own unique identificationnumber. You tentatively assign <TT>pID</TT> to <TT>pObject</TT>, and this means that<TT>pObject</TT>, at a minimum, will look like this:</P><PRE><FONT COLOR="#0066FF">class pObject{public:pObject();~pObject();pID GetID()const;void SetID();private:pID  itsID;}</FONT></PRE><P>There are a number of things to note about this class declaration. First, thisclass is not declared to derive from any other; this is your root class. Second,there is no attempt to show implementation, even for methods such as <TT>GetID()</TT>that are likely to have inline implementation when you are done.</P><P>Third, <TT>const</TT> methods are already identified; this is part of the interface,not the implementation. Finally, a new data type is implied: <TT>pID</TT>. Defining<TT>pID</TT> as a type, rather than using, for example, <TT>unsigned long</TT>, putsgreater flexibility into your design.</P><P>If it turns out that you don't need an <TT>unsigned long</TT>, or that an <TT>unsignedlong</TT> is not sufficiently large, you can modify <TT>pID</TT>. That modificationwill affect every place <TT>pID</TT> is used, and you won't have to track down andedit every file with a <TT>pID</TT> in it.</P><P>For now, you will use <TT>typedef</TT> to declare <TT>pID</TT> to be <TT>ULONG</TT>,which in turn you will declare to be <TT>unsigned long</TT>. This raises the question:Where do these declarations go?</P><P>When programming a large project, an overall design of the files is needed. Astandard approach, one which you will follow for this project, is that each classappears in its own header file, and the implementation for the class methods appearsin an associated CPP file. Thus, you will have a file called <TT>OBJECT.HPP</TT>and another called <TT>OBJECT.CPP</TT>. You anticipate having other files such as<TT>MSG.HPP</TT> and <TT>MSG.CPP</TT>, with the declaration of <TT>pMessage</TT>and the implementation of its methods, respectively.<BLOCKQUOTE>	<P><HR><FONT COLOR="#000077"><B>NOTE:</B></FONT><B> </B>Buy it or write it? One question	that you will confront throughout the design phase of your program is which routines	might you buy and which must you write yourself. It is entirely possible that you	can take advantage of existing commercial libraries to solve some or all of your	communications issues. Licensing fees and other non-technical concerns must also	be resolved. It is often advantageous to purchase such a library, and to focus your	energies on your specific program, rather than to &quot;reinvent the wheel&quot;	about secondary technical issues. You might even want to consider purchasing libraries	that were not necessarily intended for use with C++, if they can provide fundamental	functionality you'd otherwise have to engineer yourself. This can be instrumental	in helping you hit your deadlines. <HR></BLOCKQUOTE><H4 ALIGN="CENTER"><A NAME="Heading21"></A><FONT COLOR="#000077">Building a Prototype</FONT></H4><P>For a project as large as PostMaster, it is unlikely that your initial designwill be complete and perfect. It would be easy to become overwhelmed by the sheerscale of the problem, and trying to create all the classes and to complete theirinterface before writing a line of working code is a recipe for disaster.</P><P>There are a number of good reasons to try out your design on a prototype--a quick-and-dirtyworking example of your core ideas. There are a number of different types of prototypes,however, each meeting different needs.</P><P>An interface design prototype provides the chance to test the look and feel ofyour product with potential users.</P><P>A functionality prototype might be designed that does not have the final userinterface, but allows users to try out various features, such as forwarding messagesor attaching files without worrying about the final interface.</P><P>Finally, an architecture prototype might be designed to give you a chance to developa smaller version of the program and to assess how easily your design decisions will&quot;scale up,&quot; as the program is fleshed out.</P><P>It is imperative to keep your prototyping goals clear. Are you examining the userinterface, experimenting with functionality, or building a scale model of your finalproduct? A good architecture prototype makes a poor user interface prototype, andvice versa.</P><P>It is also important to keep an eye on over-engineering the prototype, or becomingso concerned with the investment you've made in the prototype that you are reluctantto tear the code down and redesign as you progress.<H4 ALIGN="CENTER"><A NAME="Heading22"></A><FONT COLOR="#000077">The 80/80 Rule</FONT></H4><P>A good design rule of thumb at this stage is to design for those things that 80percent of the people want to do 80 percent of the time, and to set aside your concernsabout the remaining 20 percent. The &quot;boundary conditions&quot; will need tobe addressed sooner or later, but the core of your design should focus on the 80/80.</P><P>In the face of this, you might decide to start by designing the principal classes,setting aside the need for the secondary classes. Further, when you identify multipleclasses that will have similar designs with only minor refinements, you might chooseto pick one representative class and focus on that, leaving until later the designand implementation of its close cousins.<BLOCKQUOTE>	<P><HR><FONT COLOR="#000077"><B>NOTE:</B></FONT><B> </B>There is another rule, the 80/20	rule, which states that &quot;the first 20% of your program will take 80% of your	time to code, and the remaining 80% of your program will take the other 80% of your	time!&quot; <HR></BLOCKQUOTE><H3 ALIGN="CENTER"><A NAME="Heading23"></A><FONT COLOR="#000077">Designing the PostMasterMessageClass</FONT></H3><P>In keeping with these considerations, you decide to focus on <TT>PostMasterMessage</TT>.This is the class that is most under your direct control.</P><P>As part of its interface, <TT>PostMasterMessage</TT> will need to talk with othertypes of messages, of course. You hope to be able to work closely with the othermessage providers and to get their message format specifications, but for now youcan make some smart guesses just by observing what is sent to your computer as youuse their services.</P><P>In any case, you know that every <TT>PostMasterMessage</TT> will have a sender,a recipient, a date, and a subject, as well as the body of the message and perhapsattached files. This tells you that you'll need accessor methods for each of theseattributes, as well as methods to report on the size of the attached files, the sizeof the messages, and so forth.</P><P>Some of the services to which you will connect will use rich text--that is, textwith formatting instructions to set the font, character size, and attributes, suchas bold and italic. Other services do not support these attributes, and those thatdo may or may not use their own proprietary scheme for managing rich text. Your classwill need conversion methods for turning rich text into plain ASCII, and perhapsfor turning other formats into PostMaster formats.

⌨️ 快捷键说明

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