[ Team LiB ] |
5.7 Document-ViewThe Document-View pattern is also known as the Document-View architecture. In this section we'll discuss a refined version of the Document-View pattern that allows for an event notification mechanism. This refined version is sometimes called the Observable-Observer pattern, or the Publisher-Subscriber pattern. The problem arises when you have a number of different representations of the same data. How do we keep the representations in synch with each other? The solution, as shown in Figure 5.9, is to have one Document Figure 5.9. The Document-View patternThe document needs to be able to add and remove views from its active list. And it needs to have a UpdateAllViews A view needs to have a getDoc() Another aspect of the Document-View architecture is that the view not only needs to be able to access the data in the document, it should also be able to mutate the data in the document. Part of the implementation of the document mutators must be that when document data is changed, the document calls UpdateAllViews Figure 5.10. Sequence diagram of a view editing a documentAs this is our first sequence diagram, we need to mention that UML sequence diagrams are used to show how the objects in a program interact over time. The diagram is set up as a series of columns, with one column for each object. Each column has a vertical lifeline showing the lifetime of the object. Arrows are drawn from lifeline to lifeline to symbolize the passing of messages via method calls. We normally label a message with the name of a method being called, and this method is expected to be a member method of the class column that the message points to. Use a dotted arrow line when the caller object is not shown. A call that an object makes to itself is drawn as an arrow that starts and ends on the object's own lifeline. The labels at the heads of the columns can either be class names or, if you want to distinguish among multiple instances of a class, you can use object names which are written in the format Class:Object1. In this diagram, we see how the View1 object can edit the Doc data and mutate it. The document mutator uses an UpdateAllViews Documents and views in Windows programsMost Windows programs use variations of the Document-View pattern to simultaneously show multiple views of multiple documents. Putting this a bit differently, the Document-View architecture allows you to have different views of the same set of data, and it also allows you to display different views of different sets of data. In a Windows Document-View architecture program you can get new views in two ways. (a) You can use a command with a name like File | New or File | Open to open an additional document, or (b) you can use a command with a name like Window | New to open an additional view of the currently active document. In case (a) what you have is a completely new set of data inside the new window, while in case (b) you get a different view of the data of one of the windows you already had open (the window which currently had the focus, i.e. the window that had the highlighted caption bar). Each onscreen window view shows the data in an associated document. It is possible to have several view windows showing the same document, but it is not possible to have one view window showing more than one document. One can imagine, say, a financial analysis program in which you might want to view the same numerical data both as a table and as a bar graph at the same time. These would be two different views of the same document, with the document being the set of numerical data. Or consider a computer game in which you want to show both a 3D rendered view of what virtual player sees, and a 2D overview map of the landscape. Here again, we'd have two views of the same document, where the document might have information like the game level, the positions of the players in the landscape, and the players' scores and strengths. In a word-processing program, the document is the text you're working on. If you use a splitter window, then the two subwindows represent two different views of the same document. In a paint or photo-retouching program, the document is the image you're working on, and you have a variety of possible views showing, for instance, different zoom levels, different layers of the image, and so on. Having the different views show the same data is not something that you get for free. You have to write code to make it happen. It used to be fairly hard to write a Document-View architecture program, but now, thanks to MFC and the 'AppWizard' (the Visual Studio tool for creating projects), it's pretty easy. When you use the AppWizard to generate some starting code for a new project, its default choice is to use the Document-View architecture. The default program architecture chosen by the AppWizard is called MDI. This uses the Document-View architecture. In Windows, Document-View architecture programs used to keep all of their views of all their documents inside a single-frame window. But now it's becoming the fashion to have a different frame window for each document. In the versions of Word starting with Word 2000, for instance, you'll find that the program pops up completely different frame windows when you open different documents. Some programs, such as Macromedia Dreamweaver, even pop up separate frame windows for each view, visually shattering the program into something like a sea of dialog boxes. But under the hood and on their menus, these are still Document-View architecture programs in which one executable manages a set of documents, each with its own set of views. The app, the doc, and the view in MFCTable 5.1 summarizes how MFC sets up the Document-View architecture for the Pop Framework. As we discuss below, not all of your application's data is supposed to go into the CDocument. A flag saying whether or not you want to mute the speaker might go into your CWinApp. And a flag saying whether you want to show you graphical objects as solids or as wire-frames might go into your CView. It's only the data that relates to the description of what you're looking at that goes into the CDocument.
This raises the point that you may want to be able to refer to one of the classes from inside one of the others. Suppose, for instance, that one of our CPopView It turns out that in terms of navigating among the app, the docs, and the views there are four tasks that we normally care about.
The first task is done by the global method ::AfxGetApp(), as in:
The second task is accomplished by the CView::GetDocument()
As it happens, you don't need the cast on GetDocument The third task is accomplished by the CDocument::UpdateAllViews The full prototype of this third method is void UpdateAllViews( CView* pSender, As we mention in Chapter 23: Programming Windows with MFC in Part II, there actually is a way to individually step through a doc's views, but this is a technique that you should use only rarely. Using UpdateAllViews The fourth task can be accomplished by a special CPopDoc::getActiveView() Documents and views in the Pop FrameworkUsing the Document-View architecture forces a programmer to think about where to declare his or her variables. In this subsection we talk about this issue in the Pop Framework. Your program is normally going to have a number of variables that describe the data being displayed by the program as well as the current state of the program. These are the kinds of variables that you might once have made into global variables or into static variables living inside your main The CDocument Let's say more about the Document-View distinction in terms of a computer game program such as we'll be writing in this book. In a computer game you'll often have an array of 'critters' moving around on top of a bitmap background. Each of your critters will have a position, a velocity, a health-index, and so on. (Normally one of the critters will represent you, the player, and its actions will be controlled by your input rather than by the program code. But it's still just a critter.) As the user plays the game, he or she will see the critters moving inside a window. It may be that if the user wants the game to run faster, he or she will have the choice of showing the critters in simple outline instead of in colorful detail. The variable controlling this choice would probably be stored at view level rather than at document level. Another example of a situation where there might be a view-specific variable might be the user's 'point of view'. This would be a factor if the critters' world is larger than the window, and the user can scroll the view this way and that. Or perhaps the world has a lot of detail and the user can zoom in or out. Or perhaps the game is three-dimensional, and the user will have the option of changing the angle of view. Two views of a Pop Dambuilder game document In our computer games, we'd expect the critters and the background bitmap information to live in the CDocument. But, as mentioned, the switch that determines whether or not to show the critters in detail would live in the CView, as would the variable (perhaps a real-valued rectangle or a matrix) that specifies the user's point of view. If you were to 'save' your game, you'd normally only want to save the states of the critters, that is the document data. But it could happen that you might want to save some information about the view as well, e.g. the current location of the player's point of view. It isn't always easy to decide whether to put a given variable into the document or into the view, but as we go along in our example programs the process should become a little clearer. Very often there is no one 'absolutely right' way to program something. (But there are plenty of things that are absolutely wrong!) For a beginning programmer, the number of choices is daunting, and it's easy to feel paralyzed with indecision. Well, the only real way to learn is by doing, so go ahead and program, but keep an open mind and be willing to go back and rewrite what you did before. Another way of putting this is that learning programming is a matter of first making every possible mistake, so the faster you make your mistakes the faster you're learning! Here's how the CPopDoc
As a sequence diagram, this looks like Figure 5.11. Since we only have one object of each class type in this picture, we just label the columns with the class names. Figure 5.11. Sequence diagram of the CPopDocument::stepDoc cascadeControlling multiple documents and viewsHow do you fit the Document-View pattern into your application if you want more than document? And how do you send messages to the various pieces of the program? One solution is to have an App Pop showing two game documents The idea is to use an App What we have here is close to a pattern called 'model-view-controller.' In the model-view-controller pattern the 'model' plays the role of the Document, the 'view' is a View This analogy is, however, imperfect, because in the specific example of MFC we actually process user commands with any of the three Document-View-App components, which in MFC are the CDocument In any case, this is a good place to say a bit about how MFC processes user commands. In MFC there is a general base class called CCmdTarget. A CCmdTarget Figure 5.12. Inheritance diagram in a multiple document patternThis diagram shows inheritance; now let's talk about composition and navigation. As we've already said, the CWinApp Figure 5.13. App and documentsThis is entirely analogous to how a Document Figure 5.14. Document and viewsFor the sake of completeness, let's draw one more UML diagram (Figure 5.15) showing some of the relationships among our Pop Framework MFC classes. Figure 5.15. Class diagram of the Pop Framework MFC classesYou might say that this UML diagram is primarily about the Windows operating system, and the UML diagram of the Pop Framework classes in the last chapter was primarily about the Pop program. It make sense that CPopDoc |
[ Team LiB ] |
No comments:
Post a Comment