Pattern-Oriented
Programming with C++
Jon Pearce
Mathematics and Computer Science Department
San Jose State University
San Jose, CA 95192
(408) 924-5065
pearce@mathcs.sjsu.edu
Preface
Pattern Oriented Programming with C++ has been successfully used as a text for university and professional C++-based Object-Oriented Programming courses and Advanced C++ Programming courses. The book introduces and makes use of design patterns, UML class diagrams, framework-based development, and advanced features of C++, including the standard template library. There are two motivations behind this approach. First, these tools are in wide use among software developers. Second, these tools are excellent pedagogical devices. Seeing plenty of design patterns helps students develop an intuition for good design, class diagrams help students visualize designs before they are obscured by mountains of code, framework-based development allows students to solve a variety interesting design problems without getting bogged down with domain-specific details, and the standard template library allows students to write complex programs without worrying about the supporting data structures.
Each chapter contains some theory mixed with several working examples that combine one or more design patterns. The motivation and design of each example is presented, followed by salient features of the implementation. To preserve readability, implementation details are relegated to notes near the end of the chapter, where subtle or advanced features of the C++ language are often highlighted. Each chapter ends with a large number of suggested programming projects. A long appendix at the end of the book presents advanced or tricky C++ "features" that appear throughout the book. Instructors can incorporate sections from this appendix into their courses as they see fit.
The chapters roughly correspond to the frameworks, services, and mechanisms one might encounter in a virtual or conceptual platform such as Java 2 (J2xE) or the Object Management Architecture (OMA):
Although the correspondences can mostly be inferred from the chapter titles, the following map might be helpful:
Chapter
2: Notification
Chapter 3: Frameworks, Virtual C++ Machine
Chapter 4: Virtual C++ Machine, Containers
Chapter 5: Persistence, Reflection
Chapter 6: Presentation, Control, Frameworks, Graphics, I/O
Chapter 7: Concurrency, Synchronization, Communication, Frameworks
While readers can learn how the components of such a platform are used and built, dependencies on specific platforms and non-standard libraries are scrupulously avoided. All programs run in a console window, save and restore objects to ordinary text files, and compile using DJGPP, a freely downloadable ISO-compliant C++ compiler for the 32-bit MS-DOS platform. (Examples also compile in versions 5.0 and 6.0 of Visual C++.) Examples and problems in the last chapter that involve graphics, multithreading, and sockets are written against a system interface that is also presented in that chapter. A short MS-Windows implementation of the system interface is provided in the programming notes at the end of the chapter.
Prerequisites
Naturally, readers are assumed to be familiar with some C++ programming, including data and sequence control, basic I/O, basic memory management, pointers, arrays, building and debugging programs, defining and calling functions, defining and instantiating classes and derived classes, and simple examples of operator overloading. Other topics, such as exceptions and the standard library, are covered in Appendix 1, while topics such as templates and virtual functions are covered in various chapters as they are needed. Occasionally, passing references to a more advanced concept, such as virtual functions or queues, might be made before the concept is explored in depth. A one year or accelerated one semester course in C++ programming has proven to be adequate for most readers.
Table
of Contents
For convenience, chapter overviews have been duplicated under each chapter heading. A list of level one (and in some cases level two) section headings follows. Page numbers have been omitted for now.
Chapter 1: Object-Oriented Modeling
A picture is worth a thousand words, or in our case, a thousand lines of code. Using UML class diagrams developers can get a quick overview of the structure of all or part of a program. Sometimes, even the quality of a design can be discerned from a class diagram.
To provide a context for modeling and design, the chapter begins with a brief overview of the iterative-incremental development process. A parallel introduction to UML class and object diagrams follows. The translation between these diagrams and C++ programs is a point of special emphasis. The chapter concludes with a discussion of design principles.
A full treatment of software engineering, UML, or design principles is beyond the scope of a single chapter and is tangential to our purposes. The interested reader should consult the references mentioned for details on these subjects.
Overview
Object-Oriented Development
UML
Objects and Classes
Links and Associations
Packages
Stereotypes
Interfaces
Interaction Diagrams
Object-Oriented Design
Problems
Broadcasters and receivers in many forms are common in event-driven programs. A broadcaster is an object that randomly broadcasts messages to unknown numbers and types of receivers. Receivers are objects that are either always on-perpetually listening or polling for broadcasts-or usually off-expecting to be awakened when a broadcast occurs. Pirate radio stations, local area networks, and underground magazine publishers are examples of broadcasters, while radios, networked computers, and magazine subscribers are examples of receivers. The mouse and keyboard of a computer can also be regarded as broadcasters, while mouse and keyboard handlers can be regarded as receivers. Because broadcast messages are un-addressed and occur randomly, they are often called events. In this case receivers are called event handlers, broadcasters are called event sources, and broadcasting is called event firing.
To avoid polling, which consumes too much time and bandwidth, many platforms provide several types of event notification mechanisms. These mechanisms can be viewed as instances of various event notification design patterns. The Publisher-Subscriber pattern is a simple and prevalent example of such a pattern. As such, it provides an excellent introduction to design patterns.
After a few background remarks on design patterns, a model of a fictional power plant is described. Various power plant sensors need to be notified when the reactor gets too hot. The Publisher-Subscriber pattern is presented as a solution to the problem. Of course event notification is important at higher levels of abstraction, too. To demonstrate this point a programmable constraint network is designed and built. (Constraint networks are closely related to spread sheets.) The role of event notification in general and of the Publisher-Subscriber pattern in particular will be revisited by the pipeline toolkit in Chapter 3 and by the application frameworks in Chapter 6.
Overview
Design Patterns
Example: Monitoring Devices
The Publisher-Subscriber Pattern
Implementing the Power Plant Prototype
Constraint Networks
Programming Notes
Problems
Chapter 3: Frameworks, Toolkits, and
Polymorphism
Polymorphism allows programmers to declare partially complete classes and functions. The idea being to complete the declaration with a subclass or a template instantiation when more application-specific information is available. Of course this is also the idea behind frameworks, toolkits, and many design patterns. In each case application-independent logic is captured by one part of the program, while application-dependent logic is concentrated in another.
After a brief survey of frameworks and a more formal introduction to polymorphism, fragments of a fictional music framework called MFW are presented as a pretext to introducing virtual functions, abstract classes, templates, and several important design patterns. These patterns and mechanisms are subsequently assembled to create a working computer game framework called FUN (application frameworks will be developed in Chapter 6) and a working toolkit called PIPES for assembling applications that instantiate the Pipe and Filter architectural pattern.
Overview
Frameworks
Polymorphism
Working with Unknown Classes
MFW: A Framework for Music Applications
Toolkits
Generic Methods
Singletons
FUN: A Framework for Adventure Games
Pipelines
PIPES: A Pipeline Toolkit
Programming Notes
Problems
Delegation allows different instances of the same class to exhibit different behaviors. In addition, the behavior of a single object can be altered dynamically. This greatly increases the flexibility of a program. Many design patterns derive their power by exploiting delegation.
Before delegation is formally introduced, the State design pattern is presented as a typical example of delegation. Next, the Adapter pattern allows readers to directly compare delegation and inheritance as reuse mechanisms. The Handle-Body pattern is introduced as a family of patterns that use delegation.
Delegation is idiomatic in C++. As a consequence, programmers must learn the Orthodox Canonical Form to handle potential memory management problems. Smart Pointers and Vectors are simple, interesting examples that demonstrate this idiom. Implementing Vectors also enhances the reader's understanding of the standard template library. Delegation can also present problems when several handles share the same body. The Reference Counting Idiom is presented as a solution to this problem. The chapter ends with the Decorator Pattern, an amusing and extreme demonstration of the power of delegation.
Overview
Objects as States
Delegation
Adapters
Handle-Body Idioms
Orthodox Canonical Form
Virtual Bodies
Smart Pointers
Containers
Vectors
Reference Counting
Decorators
Programming Notes
Problems
Chapter 5: Reflection and Persistence
A reflective architecture has two levels: a base level populated by typical application-specific classes, and a meta level populated by meta classes that describe the structure and implementation of the base level classes. By swapping or manipulating meta level objects, programmers can dynamically alter the behavior of the entire program. The Strategy pattern is a simple example of this idea.
The RuntimeClass class is a popular example of a meta level class. Instances of this class represent base level classes. Using this class programs can dynamically query objects about their types (runtime type identification). Examples and applications of this feature from LISP, C++, Java, and MFC are presented. LISP allows readers to contrast dynamic and static type systems. Java shows readers how far reflection can be taken in a statically typed language. MFC shows how much reflection is possible in C++. This is necessary to counter the impression created by the anemic RTTI feature of C++. Java and MFC programs can also instantiate instances of RuntimeClass the same way programmers instantiate classes. The Prototype pattern is presented to accomplish the same trick in C++.
Persistent objects can be saved to databases and files. After a brief survey of relational and object-oriented databases, we develop a persistence framework that uses serialization to save objects to ordinary text files.
Overview
Reflection
Strategies
Runtime Classes
Runtime Type Information
Dynamic Typing and Runtime Type Information in LISP
RTTI: Runtime Type Information in C++
Runtime Type Information in Java
Runtime Type Information in MFC
Dynamic Instantiation
Dynamic Instantiation in LISP
Dynamic Instantiation in Java
Dynamic Instantiation in MFC
The Prototype Pattern: Dynamic Instantiation in C++
Persistence
Databases
Serialization
A Persistence Framework for C++
Persistence in MFC
Persistence in Java
Programming Notes
Problems
Chapter 6: Presentation and Control
User interfaces are assemblies built out of presentation and control components. These components depend on lower level components such as graphical contexts, event notification mechanisms, and I/O streams. In this chapter we will introduce mechanisms, services, and design patterns that are important for user interfaces and application frameworks. We begin by introducing the Model-View-Controller pattern. Next, views and controllers are placed in the larger context of user interface components and graphics. Although we can't implement these classes without using non-standard, platform-dependent libraries, we can simulate them.
Next, after a brief introduction to Microsoft Foundation Classes (MFC), we define several versions of our own application framework, AFW. AFW provides architecture, a console user interface, persistence, help, exception handling, and undo/redo to its customizations. In addition to Model-View-Controller, AFW introduces several other patterns including View Handler, Command Processor, and Memento.
Overview
The Model-View-Controller Architecture
Controllers and Control
Presentation Mechanisms
Views and View Notification
Example: MFC's Document-View Architecture
AFW 1.0: An Application Framework
Resource Managers
View Handlers
AFW 2.0
Commands and Command Processors
AFW 3.0
Mementos
AFW 3.1
Programming Notes
Problems
Chapter 7: Active and Distributed
Objects
A client-server application is composed of interacting objects separated by process or machine boundaries. We call these distributed objects, because they may be distributed among machines connected by a network. Distributed objects must communicate using inter-process communication mechanisms such as mailboxes, sockets, brokers, and proxies.
A server may have many clients simultaneously making requests. In order to prevent a selfish client from starving the others, the server must create active objects- objects that "own" their own thread of control - each servicing a different client. Of course these active objects may need to share resources such as a database, data structure, or file. In this case the threads must use synchronization mechanisms such as mutexes or semaphores to prevent potentially harmful effects that may arise from simultaneous access.
In this chapter we will introduce mechanisms, services, and design patterns that are important for client-server applications. We begin by introducing concurrency and synchronization. Next, we define a C++ wrapper class for the Socket API. These ideas are combined to form a working, platform-independent, server framework. We introduce client-side and server-side remote proxies to hide sockets altogether. This allows clients and servers to communicate using remote method invocation. Finally, we decouple client and server by introducing a message passing broker.
Much of the platform dependence associated with threads, mutexes, semaphores, and sockets is hidden by a generic system interface defined in the programming notes at the end of the chapter. The programming notes also contain a Win32 API implementation of this interface.
Overview
Distributed Processing
Inter Process Communication
Concurrency
Threads
The Master-Slave Architecture
Example: The Producer-Consumer Problem
Synchronization
Direct Communication
Example: A Simple Date Client
A Server Framework
A Command Server Framework
A Command Client
Indirect Communication
Proxies
Remote Proxies and Remote Method Invocation
Brokers
Programming Notes
Programming Note 7.1: The System Interface
Programming Note 7.2: Implementing Threads
Programming Note 7.3: Implementing Locks
Programming Note 7.3: Implementing Sockets
Programming Note 7.3: Implementing Servers
Programming Note 7.3: A Win32 Implementation of System
Interface
Problems
The purpose of this appendix is to "review" certain features of C++ (and several other languages) that are used throughout the text, yet may be unfamiliar to readers. These notes are not comprehensive. Readers should consult on-line documentation, [STR], or any reasonably up-to-date reference for details.
Note
A.1: Namespaces
Note A.2: Separate Compilation
Note A.3: The Standard C++ Library
Note A.3.1: The Standard Template Library
Note A.3.1.1: Containers
Note A.3.1.2: Algorithms
Note A.3.1.3: Functors
Note A.3.2: Streams
Note A.4: Error Handling
Note A.5: Initializer Lists
Note A.6: Scope, Visibility, Extent, and Storage Class
Note A.7: Type Conversion
Note A.8: A Few Facts about LISP
Note A.9: A Few Facts about Java
The entries in this catalog are intentionally incomplete. They are intended only to outline the patterns covered in the various chapters. Readers should consult the chapter or the cited references for full accounts of these patterns.
Every C++ programmer has files of useful functions that he or she uses in almost every project. Many of the examples in the book include a file called util.h, which is listed in this appendix.
Coding
Style Guidelines
util.h
References
Books and Papers
[ALX] Christopher Alexander. The Timeless Way of Building. Oxford University Press. New York, NY. 1979.
[AND] John R. Anderson. Cognitive Psychology and It's Implications, ed. 3. W. H. Freeman and Co. New York, NY. 1990.
[ANTI] Brown, Malveau, McCormick, Mowbray. AntiPatterns. Wiley. New York, NY. 1998.
[ATK] M.P. Atkinson, P.J. Bailey, K.J. Chisolm, W.P. Cockshott, and R. Morrison. "An Approach to Persistent Programming". Computer Journal, 26(4), 360 - 365. 1983.
[BOO] Grady Booch. Object Oriented Analysis and Design with Applications. Benjamin/Cummings, Redwood City. 1994.
[COAD] Peter Coad. ???
[CON] Thomas Connolly and Carolyn Begg. Database Systems: A Practical Approach to Design, Implementation, and Management, ed. 2. Addison-Wesley, Reading, MA. 1998.
[COOP] Doug Cooper. Oh My! Modula-2! An Introduction to Programming. W. W. Norton & Co., New York and London. 1990.
[COPE] James O. Coplien. Advanced C++: Programming Styles and Idioms. Addison-Wesley, Reading, MA. 1992.
[FIRE] Morris Firebaugh. Artificial Intelligence, A Knowledge-Based Approach. Boyd & Fraser Publishing Company. Boston, MA. 1988.
[FOW-1] Martin Fowler with Kendall Scott. UML Distilled: Applying the Standard Object Modeling Language. Addison-Wesley, Reading, MA. 1997.
[FOW-2] Martin Fowler. Analysis Patterns: Reusable Object Models. Addison-Wesley, Reading, MA. 1997.
[GAB] Richard P. Gabriel. Patterns of Software: Tales from the Software Community. Oxford Press, New York, NY. 1996.
[Go4] Erich Gamma, Richard helm, Ralph Johnson, and John Vlissides. Design Patterns, Elements of Reusable Object-Oriented Software. Addison Wesley, Reading, MA. 1995.
[HORST-1] Cay S. Horstmann. Mastering Object-Oriented Design in C++. Wiley & Sons, New York, NY. 1995.
[HORST-2] Cay S. Horstmann. Mastering C++: An Introduction to C++ and Object-Oriented Programming for C and Pascal Programmers, 2 ed. Wiley & Sons, New York, NY. 1996.
[JAC-1] Ivar Jacobson, Magnus Christerson, Patrik Jonsson, and Gunnar Övergaard. Object-Oriented Software Engineering: A Use Case Driven Approach. Addison-Wesley, Reading, MA. 1992.
[JAC-2] Ivar Jacobson, Grady Booch, and James Rumbaugh. The Unified Software Development Process. Addison-Wesley, Reading, MA. 1998.
[KUN] James Kunstler. Home from Nowhere. Simon and Schuster, New York, NY. 1996.
[LAN] Thomas K. Landauer. The Trouble with Computers: Usefulness, Usability, and Productivity. MIT Press, Cambridge, MA. 1995.
[LAR] Craig Larman. Applying UML and Patterns. Prentice Hall, Upper Saddle River, NJ. 1998.
[LEE] Richard C. Lee and William M. Tepfenhart. UML and C++: A Practical Guide to Object-Oriented Development. Prentice Hall, Upper Saddle River, NJ. 1997.
[LTZ] B.P. Lientz and E.B. Swanson. Software Maintenance Management. Addison-Wesley, Reading, MA. 1980.
[MKE] J.R. McKee. "Maintenance as a Function of Design". Proc. AFIPS National Computer Conf. Las Vegas, 187-93. 1984.
[OMG] A Discussion of the Object Management Architecture. The Object Management Group, Inc. 1997.
[POSA] Frank Buschmann, Regine Meunier, Hans Rohnert, Peter Sommerlad, and Michael Stal. Pattern Oriented Software Architecture: A System of Patterns. Wiley. New York, NY. 1998.
[PEA] Pearce. Programming and Meta Programming in Scheme. Springer. New York, NY. 1998.
[PFL] Shari Lawrence Pfleeger. Software Engineering Theory and Practice. Prentice Hall, Upper Saddle River, NJ. 1998.
[POPE] Alan Pope. The CORBA Reference Guide: Understanding the Common Object Request Broker Architecture. Addison-Wesley, Reading, MA. 1997.
[ROG] Gregory F. Rogers. Framework-Based Software Development in C++. Prentice Hall, Upper Saddle River, NJ. 1997.
[ROY] W.W. Royce. "Managing the Development of Large Software Systems: Concepts and Techniques". Proc. IEEE WESTCON, Los Angeles. 1970.
[RUM] James Rumbaugh, Michael Blaha, William Premerlani, Frederick Eddy, and William Lorensen. Object-Oriented Modeling and Design. Prentice Hall, Upper Saddle River, NJ. 1991.
[SCH] Stephen R. Schach. Classical and Object-Oriented Software Engineering, ed. 4. WCB McGraw-Hill, Boston. 1999.
[SHEP] George Shepherd and Scot Wingo. MFC Internals: Inside the Microsoft Foundation Class Architecture. Addison-Wesley, Reading, MA. 1996.
[SHN] Ben Shneiderman. Designing the User Interface, Strategies for Effective Human-Computer Interaction , ed. 3. Addison-Wesley, Reading, MA. 1998.
[SOM] Ian Sommerville. Software Engineering, ed. 5. Addison-Wesley, Reading, MA. 1996.
[STR] Bjarne Stroutrup. The C++ Programming Language, ed. 3. Addison-Wesley, Reading, MA. 1997.
[WIN] Terry Winograd and Fernando Flores. Understanding Computers and Cognition: A New Foundation for Design. Ablex Publishing Corporation. Norwood, NJ. 1986.
Web Sites
Warning: web sites are more fleeting than books and papers, and of course they aren't subject to the same reviews, but some are important and unique sources of information.
[WWW-1] www.mathcs.sjsu.edu/faculty/pearce
[WWW-2] www.parc.xerox.com/spl/projects/oi/
[WWW-3] www.parc.xerox.com/spl/projects/mops/
[WWW-4] www.parc.xerox.com/spl/projects/aop/
[WWW-5] www.ibm.com/Java/Sanfrancisco/concepts/concepts.html
[WWW-6] www.rational.com
[WWW-7] www.javasoft.com
[WWW-8] hillside.net/patterns/patterns.html
[WWW-9] www.c2.com/ppr/index.html
[WWW-10] www.ibm.com/Java/Sanfrancisco
[WWW-11] www.parc.xerox.com/spl/projects/oi-at-parc/
[WWW-12] www.odmg.org
[WWW-13] www.mathcs.sjsu.edu/pearce/mfc
[WWW-14] www.omg.org
[WWW-15] www.rational.com/uml/resources