[ieee comput. soc. press 1996 australian software engineering conference - melbourne, vic.,...

9
Teaching Object Orientation: Patterns and Reuse N.A.B. Gray Department of Computer Science University of W ollongong , Northfields Avenue, NS W 2522. nabg @ cs.uow.edu.au Abstract This paper describes an advanced undergraduate "Object Oriented Programming" subject that has the aim of developing good Software Engineering practices with regard to reusable designs and reusable components. The subject utilizes framework class libraries. A simplqied framework, embodying many of the design patterns from more complex frameworks, is used to provide an ~ ~ ~ t ~ ~ f ~ ~ ~ ~ ~ ~ ~ n io frumeworks. Assignmeqts for the subject give sludents pracfice in reusing components (such as ccllection classes), standard design patterns (such as command handler chains), and complete designs for applications as provided by the frameworks. 1. Introduction 1.1. Programming and "reuse" Why has Object Oriented (00) Programming gained acceptance? The primary reason is that 00 represents another step in the progression towards higher levels of reuse. Function libraries allow you to reuse algorithms. You don't write a sine function, you use sin ( ) from the math library. You don't write a sort routine, you use qsort ( ) from stdlib. Design by top down functional decomposition allows you to consider the overall role of a program and then break it down successively until you have functions that either exist in a library or that you can write. You build up a program from a set of standard library functions and special purpose functions that generally operate on shared global data. Reusing the code for standard functions is better rewriting the code (and is a lot better than reinventing algorithms) but this style offers little more than minimal code reuse. Component class libraries and object based programs allow reuse at a larger level of granularity. You reuse complete abstract data types that package data with the functions that are to manipulate those data. You don't have to implement code to interrogate the operating system and build up a represenmion of today's date, you use an instance of class Date from the class library. You don't iniplemenl your own keyed storage structure, you use an instance of class AVL or class BTree from some library. Your approach to design changes. Your first step is to identify a partitioning of the overall program system into separate components. You then identify their classes, determining what data each instance of a class must own, and what these objects do. Some of the classes will turn out to be reusable components from a class library. Finally, you build up your program as a unique system of interacting objects. Reuse of prefabricated components like dates, lists, and trees does enhance productivity and, usually, improves reliability. The major gain tends to be from the more disciplined approach to design. The extent of actual reuse is limited. A reusable class List is preferable to a newly re-implemented version, but it is only in fist year computing science assignments that a List represents an important aspect of a programming project. Inheritance is the feature that distinguishes an object oriented from an object based style. Inheritance is a way of representing and exploiting similarities (or, if you want view things the other way, inheritance allows you to represent and exploit differences). 00 programming styles originated with simulations where it is natural to have an abstraction, e.g. class Aircraft, that represents the similar behaviours of a variety of specialized forms such as Jets, Helicopters, HangGliders etc. A simulation program can work with a collection of Aircraft, sending each messages such as "climb", "tum", or "land' and relying on each specialized type responding to the request in an appropriatemanner. Many texts and courses limit their illustrations of 00 to simple class inheritance. Thus, you see examples such as class Shape with the specializations Triangle, Square, and Circle, Or class VendingMachine with specializations CandyMachine and DrinksMachine, or a class library where inheritance is used to express relationships among different collection classes (e.g. the NIH class library [l] or Bergin's data abstraction library GI). Such simple class hierarchies provide examples of how commonalities can be exploited. Thus, the different subclasses of class VendingMachine may share the base class's member function that calculates change. Polymorphism and dynamic binding can also be 72 0-8186-7635-3/96$05.00 0 1996 IEEE

Upload: nab

Post on 13-Mar-2017

212 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: [IEEE Comput. Soc. Press 1996 Australian Software Engineering Conference - Melbourne, Vic., Australia (14-18 July 1996)] Proceedings of 1996 Australian Software Engineering Conference

Teaching Object Orientation: Patterns and Reuse

N.A.B. Gray Department of Computer Science

University of W ollong ong , Northfields Avenue, NS W 2522. nabg @ cs.uow.edu.au

Abstract

This paper describes an advanced undergraduate "Object Oriented Programming" subject that has the aim of developing good Software Engineering practices with regard to reusable designs and reusable components. The subject utilizes framework class libraries. A simplqied framework, embodying many of the design patterns from more complex frameworks, is used to provide an ~ ~ ~ t ~ ~ f ~ ~ ~ ~ ~ ~ ~ n i o frumeworks. Assignmeqts for the subject give sludents pracfice in reusing components (such as ccllection classes), standard design patterns (such as command handler chains), and complete designs for applications as provided by the frameworks.

1. Introduction

1.1. Programming and "reuse"

Why has Object Oriented (00) Programming gained acceptance?

The primary reason is that 00 represents another step in the progression towards higher levels of reuse.

Function libraries allow you to reuse algorithms. You don't write a sine function, you use sin ( ) from the math library. You don't write a sort routine, you use qsort ( ) from stdlib. Design by top down functional decomposition allows you to consider the overall role of a program and then break it down successively until you have functions that either exist in a library or that you can write. You build up a program from a set of standard library functions and special purpose functions that generally operate on shared global data. Reusing the code for standard functions is better rewriting the code (and is a lot better than reinventing algorithms) but this style offers little more than minimal code reuse.

Component class libraries and object based programs allow reuse at a larger level of granularity. You reuse complete abstract data types that package data with the functions that are to manipulate those data. You don't have to implement code to interrogate the operating system and build up a represenmion of today's date, you use an instance of class Date from the class library. You don't iniplemenl your own keyed storage structure, you use an

instance of class AVL or class BTree from some library.

Your approach to design changes. Your first step is to identify a partitioning of the overall program system into separate components. You then identify their classes, determining what data each instance of a class must own, and what these objects do. Some of the classes will turn out to be reusable components from a class library. Finally, you build up your program as a unique system of interacting objects.

Reuse of prefabricated components like dates, lists, and trees does enhance productivity and, usually, improves reliability. The major gain tends to be from the more disciplined approach to design. The extent of actual reuse is limited. A reusable class List is preferable to a newly re-implemented version, but it is only in f is t year computing science assignments that a List represents an important aspect of a programming project.

Inheritance is the feature that distinguishes an object oriented from an object based style. Inheritance is a way of representing and exploiting similarities (or, if you want view things the other way, inheritance allows you to represent and exploit differences). 00 programming styles originated with simulations where it is natural to have an abstraction, e.g. class Aircraft, that represents the similar behaviours of a variety of specialized forms such as J e t s , Helicopters, HangGliders etc. A simulation program can work with a collection of Aircraft, sending each messages such as "climb", "tum", or "land' and relying on each specialized type responding to the request in an appropriate manner.

Many texts and courses limit their illustrations of 00 to simple class inheritance. Thus, you see examples such as class Shape with the specializations Triangle, Square, and Circle, Or c l a s s VendingMachine with specializations CandyMachine and DrinksMachine, or a class library where inheritance is used to express relationships among different collection classes (e.g. the NIH class library [l] or Bergin's data abstraction library GI).

Such simple class hierarchies provide examples of how commonalities can be exploited. Thus, the different subclasses of class VendingMachine may share the base class's member function that calculates change. Polymorphism and dynamic binding can also be

72 0-8186-7635-3/96 $05.00 0 1996 IEEE

Page 2: [IEEE Comput. Soc. Press 1996 Australian Software Engineering Conference - Melbourne, Vic., Australia (14-18 July 1996)] Proceedings of 1996 Australian Software Engineering Conference

illustrated; thus, one can have a list of Shape* pointers and a function that works along the list telling each Shape to draw itself and compute its area.

These hierarchies can also show how code can be made more general, and how it is possible to avoid premature design decisions. For example, a unified collection class hierarchy allows a program to be written relying on the use of an instance of an abstract Collection class, while deferring decisions as to the particular concrete implementation.

Such uses of inheritance can improve design and reuse to a small degree. However, the classes in these hierarchies are very much stand alone. They have no predefined relationships with other classes. As such, they fail to take full advantage of the 00 approach.

1.2 .00 and "design reuse"

00 allows exploitation of similarities. This need not be limited to similarities in specific behaviours of objects that are instances of related classes. Many programs have substantial similarities in their overall operation.

Just think about the way the different word processor, spreadsheet, diagram drawing and other programs work on your personal computer. They all have the same arrangements of "window", "menus", "undo/redo" editing operations and so forth. Obviously, they all have a lot of rather similar code. The data drawn in the windows and the available menu commands will differ. But all programs must use very similar code for a sequence of actions like picking up a mouse click, recognizing it as a menu selection, and then determining which menu option.

If you abstract out this similar code, you can greatly decrease the cost of developing new applications. The new applications can reuse not just individual classes, but clusters of classes where standard patterns of interactions are already defined.

The class hierarchies of the individual classes involved in such clusters again reflect similarities among related components. For example, a cluster might include classes from a "Windows" hierarchy that has subclasses representing many kinds of specialized Window; similarities among windows would be represented through this hierarchy.

The class cluster itself captures something rather greater. A cluster captures similarities among applications (programs). The pattems of interactions among the classes of a cluster can represent a relatively complex overall behaviour.

Such a pattern might constitute a general solution to a common problem. For example, the "Chain of Command" pattern 131 is a standard mechanism for identifying the specific object that should handle a given user input in an interactive program.

Alternatively, a pattern may define a behaviour required by the "look and feel" guidelines for applications developed on a given platform. For example, when an Application object is told to "quit", it may be required to

first give each open Document object a chance to save any altered memory-resident data to their corresponding files.

These clusters contain a number "partially implemented abstract classes". "Partial implementation" describes the way that standard behaviours are already encoded in member functions of the class cluster. The member functions for one class will invoke behaviours of instances of other classes in the cluster. For example, the function Application: : DoQuit ( ) might include Code Of the form "for document in document-list do document- > AboutToQuit()", with the function Document: : AboutToQuit ( ) containing code like "iffthis -> Changed0 & & gDialogManager->Savechanges Dialog()) this- >DoSave()".

Although such code defines the overall behaviour, vital bits are missing. Thus Document : : DoSave ( ) may be a pure virtual function or have simply an empty body. It represents a function that must be replaced in any concrete class derived from the cluster's Document class.

The clusters may actually include some concrete classes. For example, the cluster might include "dialogs" with "text item" and "number item" objects that can accept keyed input. Like collection classes such as lists, these user interaction elements can be used as "off the shelf" components. Developers don't need to extend these classes; instances can be instantiated and used as required.

Such class clusters raise "reuse" to a new level. A cluster embodies a finished design for a particular aspect of an application. For example, a "command handler" cluster with classes Application, Document, Window etc implements a design for a program, any program, that has documents (associated with disk files) whose contents are to be displayed in windows. Programs created using the cluster will respond in the "standard way" to all standard commands like Filemew, File/Open, File/Quit. In some cases, the code of a class cluster can actually be compiled and linked and will run, workiilg "correctly", albeit with blank windows and empty files.

When the basics of launching a program, opening file(s), and creating windows are handled by the standard code, developers can focus more on those aspects that make their program unique. Their program has specific data structures that are owned by the documents and are transferred between memory and disk files. So they must define class OurDoc : public Document with extra data members to store the problem specific data and they must provide effective implementations of functions such as OurDoc : : DoSave ( ) and OurDoc: :DoRestore ( ) . Similarly, the developers will have to provide effective implementations for the function(s) that display mme representation of their data in a window.

Part of the work of the developers of a new program involves the definition of new classes that inherit from partially implemented abstract classes defined in a "framework class library. This work involves essentially no new design. The framework classes provide the basic reusable design; the developers need only provide implementations of a few specific routines.

73

Page 3: [IEEE Comput. Soc. Press 1996 Australian Software Engineering Conference - Melbourne, Vic., Australia (14-18 July 1996)] Proceedings of 1996 Australian Software Engineering Conference

The rest of the work, i.e. the application specific aspects, will involve design studies. The developers must identify the data that are to be represented and must determine how a user may create, subsequently modify, and eventually use the data.

Unlike the reuse of component, e.g. a collection class such as a list, the reuse of an elaborate class cluster or framework can make a substantial difference to developers' productivities. Programs built using frameworks are delivered faster and are much more likely to comply with "look and feel" guidelines than those developed independently.

It is this style of usage that represents the real power of the 00 approach. An 00 programming course should lead into the use of recognized design patterns [3] and reusable frameworks [4].

2. Course structure

2.1. Simple use of classes and inheritance

The 00 programming course described here is a final year elective in the undergraduate program. The course originated in 1988 and has been evolving steadily. Currently, the C++ language is used. The normal programming background for enrolled students has been one year's experience with C (with minor use of C++), following an initial year using Modula2.

The students have already studied abstract data types, implemented using Modula2 and C modules and also as simple C++ classes. The 00 programming course starts by revising the use of simple C++ classes as a mechanism for implementing abstract data types and by covering genericity (C++ templates etc).

The "oriented" part of the course starts with simulation examples. A standard example uses a Moria (Rogue) like game where the player seeks to explore a maze despite resistance from the maze's inhabitants. The maze is inhabited by numerous creatures drawn from different races. All creatures have essentially the same behaviour (they seek to end the game by eliminating the human player), but each different kind (class) of creature goes about this task in a distinct way. The game program works with a collection of creatures. At appropriate times, the creatures get their chance to proceed. The code is simple: "for each creature in creature list do creature.run". Here the reference variable creature is polymorphic, as we move along the list the variable creature may reference fxst a ghost, then a troll, etc.

The assignments performed at this stage by students are similar though more prosaic. Their programs simulate things like "activities" in a supermarket (with activity subclasses including things such as checkouts and customers). Such simulation examples provide an easy introduction to the use of class hierarchies, heterogeneous collections, and polymorphic pointers as well as an opportunity to reuse standard components such as lists. The nature of the examples is such that there is rarely any

difficulty in recognizing the objects and their classes during the design process.

2.2. Using framework libraries

The main aim of the course is however to get the students familiar with the reuse of designs and frameworks. This objective is similar to that of Huni and Metz with their "Games Factory" [5] but here the examples are much more closely tied to the intended subsequent work with full scale frameworks [4].

The standard Graphics User Interaction (GUI) frameworks are used. These GUI frameworks include for Intel architecture: Borland's Object Windows Library (OWL) [61, and Microsoft's Foundation classes (MFC) [71; for Macintosh: Symantec's Think Class Library (TCL2) [8] and Apple's MacApp [91; while for Unix there are analogues like ET++. [ 101

However, there are some problems related to the introductory use of such frameworks. They are all relatively "mature" systems intended for commercial product development, and consequently they are elaborate with literally hundreds of classes. Some frameworks are poorly documented. Consequently, the frameworks are somewhat intimidating on first encounter. Despite these complexities and other problems, use of the frameworks is possible, provided that there is a suitable introduction.

The RecordFile framework class library described in the subsequent sections has been introduced to serve as a simple generic introduction to the GUI frameworks. It embodies much the same conceptual model for a program, though in a considerably more restricted and hence simpler form. The framework is used in an introductory exercise and assignment to illustrate general principles before students start work using one of the main GUI frameworks. This introductory assignment gets students to create new classes that inherit from "command handler" and other classes provided by the framework as well as using concrete components like "file dialogs".

The final part of the course involves two small assignments illustrating the use of a standard GUI framework class library and the development by each student of their own framework-based application. The first of these assignments will usually involve just input and editing of data using standard concrete class components (e.g. a "number input" object); the second assignment is generally some variation on a graphic editor. Details of the independent project are given later.

3. The RecordFile Framework

3.1. Program design embedded in RecordFile

Frameworks are designed to provide a basic structure for solving problems in a particular restricted domain. The problem domain for the RecordFile framework is one that is familiar to both students and their instructors. It is the domain of "file of records".

74

Page 4: [IEEE Comput. Soc. Press 1996 Australian Software Engineering Conference - Melbourne, Vic., Australia (14-18 July 1996)] Proceedings of 1996 Australian Software Engineering Conference

Typical first year programming courses introduce "records" (as Pascal/Modula2 records or C smcts) toward the end of the first semester or at the start of the second semester. Shortly afterwards, files of records (either sequential or random access files) are added. Favoured assignments have the students writing programs that work with "student records" (name, subject, several assignment marks), or "customer records" (name, address, item on order, date), or "loan records" (name, names of movieshooks on loan). Records have unique identifier keys such as a "student number", or "customer identifier". The program must load and display existing records, permit changes to existing records and allow for the addition (and possibly deletion) of records.

Such programs have very similar structures. In fact, the only things that really differ are the record and the form of the "display" used to show a records content and to permit changes to fields. The commonalities can be captured in a simple framework.

The classes in the framework are summarized in Figure 1. Unlike some of the older frameworks (MacApp, MFC, ET++), these classes do not share a single root like class ob j ec t . Instead, there are a number of separate hierarchies, only the "windows hierarchy" has any real complexity.

The classes include a "record" class, some standard collection classes, simplified Application and Document classes modelled on those in the standard GUI frameworks, and a set of "windows" classes. The framework uses a simple cursor-addressable ("curses") style of window display. class WindowRep is a "wrapper" class that hides the low-level operating systems dependent aspects of cursor-addressing; it relies on a common subset of the "curses"-like mechanisms that exist on Unix, PC, and Macintosh (Symantec) systems. An example display, from a Macintosh implementation, is shown in Figure 2.

- Record Application,

Collections Document, etc Windows

Figure 1. Classes in the RecordFile framework.

75

Page 5: [IEEE Comput. Soc. Press 1996 Australian Software Engineering Conference - Melbourne, Vic., Australia (14-18 July 1996)] Proceedings of 1996 Australian Software Engineering Conference

Figure 2. Example record display.

The basic behaviour of a program built using the RecordFile framework is as follows:

The Application object presents the user with a "new file, open file, quit" menu. Selection of either of the "file" options results in the creation of a Document object (which will "load" data from any existing file). The Document displays its menu. The choices for the user are now "close, new record, delete record, view/edit record". Choices involving records result in the display of a dialog that gets a record number . If the user chose to create a new record, or to view an existing record, the display changes to something like that shown in Figure 2. The display will now be comprised of label fields, non- editable output fields (e.g. the "Total" field in Figure 2) and editable numeric and text entry fields. The user can "tab" between editable fields and type data into fields whose contents should be changed (inputs are verified against field specified constraints). The data members in the record associated with the display are updated as changes are made. When data enuy and review is complete, the user may type "enter" to return to the Document object's menu display.

0 The Document object handles a "close" command by closing associated file(s) and then returns control to the Application object. This again offers its "new, open, quit" menu. The program terminates when the user selects "quit".

Those familiar with the GUI frameworks will have observed that the flow of control is far more constrained than is typical. This is probably the major simplification in this frameworks code.

3.2. Framework classes and their interactions

Document object's can work with memory resident collections or disk based collections of records. The memory resident versions can employ simple lists or dynamic arrays to hold the records, or may use more sophisticated collections (e.g. an AVL-tree class). The disk based collections use an instance of a BTree class to organize data records in disk files and arrange for loading of records on demand. The students are familiar with these structures having seen them earlier in an "abstract data types" subject in which the collections were implemented either as C++ classes or C "modules". CommandHandlers (i.e. Document and Application

objects) work with Menuwindows. class Menuwindow has a member function, AddMenuItem( char* name, int cmdNumber) , that is used to set the options. A Menuwindow handles input, ignoring all characters save "tab" and "enter"; tabs change the current selection, "enter" results in the Menuwindow retuming the command number associated with the currently selected menu item.

A Record uses a RecordWindow when interacting with the user. Like a dialog in any of the standard GUI frameworks, a RecordWindow owns a list of subwindows. Some of the subwindows may be only for output, most subwindows will display editable data. A Record creates both its Recordwindow and the subwindows needed; adding the subwindows to the Recordwindow.

A Recordwindow responds to tab characters by changing the editable subwindow responsible for handling subsequent input. An EditText subwindow accepts all printable characters, while an Edi tNum accepts digits; subwindows relinquish control to their enclosing Recordwindow when given characters like tab or enter. The Recordwindow can ask a subwindow whether its

76

Page 6: [IEEE Comput. Soc. Press 1996 Australian Software Engineering Conference - Melbourne, Vic., Australia (14-18 July 1996)] Proceedings of 1996 Australian Software Engineering Conference

contents have been changed. If the data were changed, the Recordwindow informs its Record, providing details of the subwindow affected.

The Record can update its own data members by asking the subwindow for the new data.

Most of the code needed to handle the interactions among objects is provided by the framework classes. For example, a "Document/New record" menu selection is processed using the DoNewRecord ( ) and DoEditRecord ( ) functions:

void Document::DoNewRecord() {

long key = GetKeyO; if(keyi=O)

return; Record *r = DoMakeRecord(key); DoEditRecord(r); fStore->Append(r); fStore->Save(r) ;

I

void Document::DoEditRecord(Record *r) I RecordWindow *IW = r->

rw->PoseMOdally ( ) ; delete IW;

DoMakeRecordWindow() ;

The record is created, gets told to make its window, uses its window to interact with the user, and then later gets added to the collection. The user interactions are handled in the Recordwindow object's PoseModally ( ) function which invokes actions by the various EditText, Edit" subwindows and the Record involved:

void RecordWindow::PoseModally() I

// I n i t i a l i z a t i o n char ch;

DisplayWindow(); ...

// Loop until user ends i n p u t w i t h " e n t e r ' do { // A c t i v a t e n e x t e d i t subwindow,

NextEditwindow(); ...

// Subwindow g e t s i n p u t up t o a // terminator character ( re turned)

ch = fEMLn->GetInput ( ) ; if(fEWin->ContentChanged()) {

// Update record f Record->

fRecord->

I

ReadDisplayField(fJ3Wi.n);

ConsistenqUpdate(fEWin) ;

} while(ch ! = e n t e r ) ; 1

The complete code for the framework, and associated examples, can be covered in a two lhour lecture. Usually more time would be needed to comment on and elaborate on some of the standard interaction pattems that occur in the code. The standard examples illustrate the use of two different collection classes: an in memory dynamic array and disk based storage using a BTree.

3.3. Creating a specific program

A program can be built on the framework by providing specialized versions of the classes Record, Application, and Document. The specialized "MYDOC" class is actually derived from a framework provided subclass of class Document. Figure 1 shows classes BTDoc and ArrayDoc.

The fra"0rkS Application and Document classes require only minor extension to get a working program e.g.:

class StudentMarkApp : public Application { protected:

}:

virtual Document" DoMakeDocumentO;

class StudentMarkDoc : public BTDoc { protected:

virtual Record *DoMakeRecord( long recnum);

I ;

The implementation for their member functions is as expected:

Document *StudentMarkApp::DoMakeDocument() I

I return new StudentMarkDoc;

Record *StudentMarkDoc::DoMakeRecord(

I

1

long recnum)

return new StudentRec (recnum);

The specialized subclass of class Record does have some substance, but it is all quite simple, e.g. :

class StudentRec : public Record { public :

StudentRec (long recnum) ;

// Redef ine KeyedStorableItem f u n c t i o n s virtual void WriteTo(fstree out)

virtual void ReadFrom(fstream& in); const;

... // R e d e f i n e Record functions virtual void SetDisplayField(

Editwindow * e ) ; virtual void ReadDisplayField(

Editwindow *e) ;

77

Page 7: [IEEE Comput. Soc. Press 1996 Australian Software Engineering Conference - Melbourne, Vic., Australia (14-18 July 1996)] Proceedings of 1996 Australian Software Engineering Conference

protected: virtual void ConsistencyUpdate(

virtual void AddF'ieldsToWindow(); // Declare unique data members char f StudentName [ 64 I ; long fMarkl;

long fTotal;

Edi tWindow *e) ;

... 1;

The function AddFieldsToWindow ( ) populates the Recordwindow with the necessary EditText and Edit" editable subwindows:

void StudentRec::AddF'ieldsToWindow() {

Record::AddFieldsToWindow();

// Adding an Ed i tText EditText *et = new EditText(lOO1, 5, 4 ,

fRW->AddSubWindow(et); 60, "Student Name " ) ;

... 1

Functions SetDisplayField ( ) and ReadDisplay Field ( ) transfer data to/from the EditText and Edit" windows.

The ReadFrom( ) and WriteTo ( ) functions involve a series of low level read (write) operations that transfer the data for the individual data members of the record:

void StudentRec::ReadFrom(fstream& in) {

sizeof(fRecNum));

sizeof(fStudentName));

I

in. read ( ( char* ) &f RecNum,

in.read( (char*)&fStudent"e,

...

Assignments using the framework involve use of different records, different collection classes and extensions such as "caching" of disk based records.

4. Patterns illustrated in the RecordFile Framework

The framework code illustrates some of the simpler patterns from reference [3].

For example, although a program may have many windows, they all share the same screen. Access to the screen is controlled by an instance of the "wrapper" class WindowRep. There should only be one WindowRep object in control of the screen. All the different window objects need to access this screen controller object. It has to perform some initialization tasks the first time that it is used. Given these characteristics, it is appropriate to make the WindowRep class a "singleton":

class WindowRep { public :

static WindowRep *Instance(); void PutCharacter(char ch, int x,

void Beep() ; void Delay(int nseconds);

int y);

... private :

WindavReg ( ) ; void Initialize ( ) ; void PutCharacter(char ch); stat ic WindawRep *sWindmRep; char fImage [CG-HEIGHT] [CG-WIDTH1 ; ...

} ;

Code using the WindowRep object follows the standard "singleton" idioms, e.g.:

void InputFileDialog::PoseModally( char *current, char newdata[], int checked)

DisplayWindowO; for(;;) I // Loop until v a l i d f i l e name g iven // Get a f i lename

I

... // T r y opening f i l e

// return i f OK if (state)

// Warn o f i n v a l i d f i l e name WindcwReg : : Instance ( ) ->Beep ( ) ; fE->SetVal( "File not found", 1) ; WindcwRep: :Instance() ->Delay(l);

...

return;

Several different collection classes were available from an "abstract data types" subject. These included lists, dynamic arrays, binary tree, an AVL tree, and a BTree class. Their class interfaces were not identical. The framework code needed to work with a "collection". Use of the existing classes naturally lead to "adapters". The framework classes, such as BTCollection in Figure 1, illustrate the Adapter pattern from reference [3].

Functions such as Document : : DoMakeRecord ( ) and

examples of the "Factory Method" pattern. This pattern removes from the framework code all program specific details related to the exact type of record or document that must be created.

The relatively simple and short code of the RecordFile framework makes it easier to illustrate the implementation of these standard patterns and to explain their use.

Application: : DoMakeDocument ( ) are standard

78

Page 8: [IEEE Comput. Soc. Press 1996 Australian Software Engineering Conference - Melbourne, Vic., Australia (14-18 July 1996)] Proceedings of 1996 Australian Software Engineering Conference

5. Use of the GUI frameworks

The final part of the course involves the development by each student of their own framework-based application. The students have to propose an appropriate project, provide a specification, initial documentation, an implementation, and final detailed class documentation. Students chose a specific environment for their two small framework based exercises and their project. The normal choices are Borland's OWL framework for the PC, Symantec's TCL2 for the Macintosh, and ET++ for those who prefer to work on Unix.

The initial documentation is supposed to include scenarios illustrating the objects and interactions involved when the proposed program is handling various aspects of its work. Designs are documented using diagrams and pseudo-code. The design diagrams used include simplified versions of some of the design notations of Booch [ l l ] as well as object interaction diagrams like those in reference [31.

Past generations of students have chosen:

Games: There have been large numbers of versions of poker machines and blackjack (presumably most students spend their evenings playing the pokies at the nearest pub). More elaborate games have been attempted, e.g. "Snakes and Ladders" and similar games (usually for two or more human players with the computer's role just handling the display); and there have been variations on "Lemmings", "Tetris", and "Asteroids". Games tend to be on the easy side in terms of 00 design, and they make limited use of the framework (framework facilities are used to set up an initial state and get parameters, after that special purpose code takes control). Consequently, they are not the best projects.

Another popular variation has been something like the type of application that can be built with the RecordFile framework, though built with the full GUI framework. A typical example program was one that maintained members' score cards for a golf club.

Graphics editors are slightly less common because they involve relatively large amounts of code. Editors have included circuit layout programs, musical score editors, editors for architectural drawings, and an editor for creating maps for "Dungeons and Dragons" games.

We've had "air traffic control" simulations, ecology simulations, and models of message passing in the Internet. Simulation programs vary. The best have a simple editor component that lets the user set up the system to be simulated, then a simulation component that demonstrates how things change.

Over the years, individual students have created a number of quite successful programs, including a jigsaw

Data collections:

Editors:

Simulations:

Individual achievements:

puzzle program for small children, a simplified "Paint" program again for preschoolers, "Maze explorer" (a version of "Doom" but with no one to shoot at), spreadsheets, a useful music editor, and a "movie collection program" (with links to MPEG film clips and audio tracks).

Although the majority of the applications developed by the students are simple, they do give the students sufficient initial experience with the framework environments so that subsequently more ambitious projects can be undertaken. Essentially all projects for Macintosh and PC platforms should nowadays be done at the framework level rather than the much lower "Applications Programmer Interfaces" provided by these OSs.

6. Conclusions

The course has over the last few years successfully introduced students to the concept of reusable designs such as those embodied in the frameworks. The RecordFile framework has been recently introduced to ease the process of learning to work with a framework and to serve as a specific model of abstract design pattems. (Code for the framework and additional documentation is available via the World Wide Web [12].)

Our overall course structure is changing with object- based design styles now being accorded consisderably more time in the early undergraduate curriculum. In future, students entering the 00 programming subject will have substantial experience of using C++ classes for data abstraction and template-style genericity. This will allow the course to focus even more strongly on the "reuse of design pattems".

References

[41

PI

K.E. Gorlen, S.M. Orlow, and P.S. Plexico. Data Abstraction and Object Oriented Programming in C+ +, John Wiley, 1990 J. Bergin. An Object Oriented Course in Data Abstraction. Computer Science Education, (OOPSLA Educators Forum issue), 4,63-76, 1993. E. Gamma, R. Helm, R. Johnson, and J. Vlissides. Design Patterns: Elements of Reusable Object Oriented Software, Addison-Wesley, 1995. T. Lewis. (Ed.). Object Oriented Application Frameworks. Manning, 1995. H. Huni, I. and Metz. Teaching 00 Software Engineering by Example: The Games Factory. Computer Science Education, (OOPSLA Educators Forum issue), 4, 111-121, 1993. Borland Objectwindows for C c c, Programmers Guide. Borland International, 1993. Microsoft Visual C++, Class Library Reference for the Microsoft Foundation Class Library. Microsoft Corporation, 1993. Symantec C++, Think Class Library Reference. Symantec Corporation, 1994.

79

Page 9: [IEEE Comput. Soc. Press 1996 Australian Software Engineering Conference - Melbourne, Vic., Australia (14-18 July 1996)] Proceedings of 1996 Australian Software Engineering Conference

[9] Programmers' Guide to MacApp, Developer Technical Publications, Apple Computer, 1992.

[lo] A. Weinand, E. Gamma, and R. Marty. ET++: an object oriented application framework in C++. in Proceedings of the Object-Oriented Programming Systems, Languages, and Applicatiom Conference, 45-57, ACM, Sept. 1988.

[ll] G. Booch. Object-oriented analsys and design with applications, Benj amin/Cummings, 1994.

[12] Code and documentation available at: http://www. cs .uow .edu.aulpeoplelnabglABC/ABC .html.

80