Programming with Purpose Series: Understanding and Using Patterns

By: Paul Gustavson

Abstract: This paper examines how to build software more effectively and efficiently using patterns. We explore the various types of patterns, and how patterns can be identified and documented using Borland Together. We also examine how patterns can enable greater reuse of component models for C#, C++, Delphi, and JBuilder developers.

Paul Gustavson is a cofounder of SimVentions, Inc and supports a wide variety of software development, modeling and simulation, and Web technology efforts. An accomplished C++ and Delphi developer, Paul has been a long time user of Borland's developer tools starting with Turbo Pascal in 1983. He has written and presented numerous publications on simulation interoperability and software development, and is a co-author of "C++Builder Developer's Guide (2nd Edition)", a contributing author to "C++Builder 5 Developer's Guide", and the technical editor for SAMS Teach Yourself UML (2nd Edition).

pgustavson@simventions.com

Programming with Purpose Series: Understanding and Using Patterns

Programming with Purpose: Understanding and Using Patterns

Paul Gustavson
SimVentions, Inc.

11903 Bowman Drive, Suite 102

Fredericksburg, VA 22408
pgustavson@simventions.com

 

Type: Regular Session

Level: Intermediate

Description: This session examines how to build software more effectively and efficiently using Patterns.  Well explore the various types of Patterns, and how Patterns can be identified and documented using Borland Together.  Well also examine how Patterns can enable greater reuse of component models for C#, C++, Delphi and JBuilder developers.

Prerequisites: Participants should have some familiarity with object oriented software

Abstract:

Key to any successful development project is to clearly identify the requirements and functionality to be represented within the applications that are going to be built.  The goal at this early stage of the development process should be to define model specific representations of the required functionality.  Patterns provide a highly useful mechanism for defining the activities necessary to support common themes (or problems) that are to be handled in a system or application being developed.  In this session we explore how to define a model specific representation of a programs functionality using patterns.  We show how to identify patterns and reuse them.

 

This session explores how to begin to uncover Patterns for a targeted software project and how these patterns can be represented as UML diagrams developed using Borland Together.  We examine how patterns can be used to bring conceptual models to life. 

 


1           Introduction

 

Software development is an art  or at least it can be.  The distinguishable criterion of the artistic developer is not necessarily their level of experience or language knowledge, its that that they have the ability to conceptualize and bring to life software that matches or exceeds purpose and intent.  I use the term distinguishable, because, in the examination of the product produced, the quality of the conception or execution, which is embodied by the software, can be easily discerned and ultimately appreciated by those that use it.   That, in it its very nature, is the manifestation of art.

 

Perhaps you have the knack of understanding whats needed and knowing how to weave and spin code and produce something that hits the mark regarding form, function and fit.  Or, perhaps, youd like to have that knack; your desire is to be able to produce code and generate applications that are art worthy  that is, it is well regarded and appreciated.  In this paper, we will examine how the identification and codification of patterns can advance and even transform your approach, giving you an artist touch, and perhaps even renew your passion for software development if its been lacking.  Well also discover how patterns can enable reuse and expedite the development process.

 

1.1       Form, Function and Fit

 

Before we get into the concept of patterns, lets understand what we mean by the terms form, function and fit, which were used earlier.  These are terms used to identity different characteristics and qualities.  The questions that can be asked in examination of the software produced in regards to these qualities include the following:

 

Form  does the application produced take the shape, structure and appearance one would expect or hope for?

 

Function  does the application produced support the purpose and objectives and provide the capabilities one would expect or hope for?

 

Fit  is the application robust, healthy, and capable of running for extended periods of time without hiccupping on user entries, data overloads, or bogging down the CPU or network?

 

1.2       Focus

 

Form, Function and Fit are all influenced by the following aspects:

 

(a)     understanding the problem domain

(b)     understanding the requirements or desired capability

(c)      understanding the language and environment for which you are developing

(d)     understanding how to conceptualize and bring the idea to life via   software

 

Certainly there are other aspects that influence software development including time, tools, and often funding, but those aspects dont necessarily influence creativity.  Creativity is the necessary vehicle for the production of art, and, in our case, software!   Creativity coupled with the right focus can help us conceptualize and bring an idea to life.   That focus can be achieved by applying a pattern approach to our software development process.

 

Therefore, to achieve form, function and fit, we need focus. Patterns provide one proven yet little used way to attain focus.   In this paper we will explore the concept of patterns, how to begin to look for patterns, and how to document Patterns using UML through a tool like Borland Together.

 

2          What is a Pattern?

 

In his book, The Timeless Way of Building, architect and professor Christopher Alexander formally introduced to the architectural world the concept of patterns. He recognized that common design elements exist in architecture that, if identified, would simplify and advance the process of building.  As a follow on, Alexander wrote the book, A Pattern Language.  From that book we were offered the following definition of a pattern.

 

Each pattern describes a problem which occurs over and over again in our environment, and then describes the core of the solution to that problem, in such a way that you can use this solution a million times over, without ever doing it the same way twice. [Christopher Alexander (A Pattern Language  x)]

 

Alexanders books and ideas had such a profound influence that members of the software development community began to take notice.  The concept of patterns has been seen as a key enabler in providing focus to software developers and encouraging composability and reuse. Gamma, Helm, Johnson and Vlissides authored a turnkey book for the object oriented software community titled Design Patterns - Elements of Reusable Object-Oriented Software, which is commonly referred to as the Gang of Four (GOF) book in respect for the four authors who authored it.   They explain that a pattern is like a template that can be applied in many different solutions. [GOF - pg. 3]

 

In more general terms, Martin Fowler, who wrote a complementary pattern book of his own titled, Analysis Patterns  Reusable Object Models, defines a pattern as, an idea that has been useful in one practical context and will probably be useful in others. [Martin Fowler (AP)].  In his book, Fowler explores how patterns can be used not only to support the design phase as the GOF book identifies, but also the analysis (define) phase of development.

 

In the context of this paper, we state the following:  A pattern identifies a set of elements used to accomplish or support a common need, capability or purpose. 

 

In other words, a defined pattern reflects what activities take place and what resources (classes and objects) are needed to carry out an identified objective.  Ralph Johnson, co-author of the GOF book, offers the following insight.  Patterns are supposed to describe reality, not invent a new one. [Ralph Johnson (AP -v)]. 

 

Johnson adds that, one of the biggest advantages of patterns is that they help us communicate better. [Ralph Johnson (AP - vi)].  Lets face it!  Communication is often a real problem among members of a software development team.  While requirements may be understood, and every member may be responsible for a design and development task, communication takes a back seat until after the product is tested. What is lacking is information sharing during the design and development stages. This communication / information sharing problem is even greater among similar yet distinct development teams within an organization or company.   I have experienced first hand situations where a developer within a development team has spent an exorbitant amount of time designing a solution to a problem only to find out much later that another individual or another development team within the company conquered the same problem for a different requirement or project.  Two things become apparent in these situations:

 

(a) the teams members and development teams are not effectively sharing their design solutions to common problems, and

(b) there is not a common approach that has been adopted for describing and sharing these solutions. 

 

The solution offered in this article is that design patterns provide the essential metadata that helps improve communication and facilitate greater reuse of designs and ultimate software modules.

 

Additionally, the flexibility offered by many of the patterns that we will explore can be useful to describe both high-level conceptual models (i.e. system-of-systems) and also can be used to describe low-level models (i.e. system subcomponents). 

 

3          How to Recognize Patterns?

 

The key in recognizing patterns is to look for the activity of relationships among the conceptual entities, which are to be represented, early in the development process.   

 

As software developers, we tend to jump straight into defining the pieces (classes and objects) we believe are necessary to support the requirements, at least as we interpret the requirements. Once we think we know what pieces are needed, we are then anxious to go off and develop them. However, this short-cut mentality often leads developers to a point where back-tracking and reconciliation is required.  What often needs to be reconciled, after we have already defined, designed and developed the individual pieces, is the relationship and influence these pieces will have on one another. Otherwise, piece-mealing it all back together doesnt necessarily result in a design or a product that fulfills the overall objective. It doesnt support the big picture.  Alexander considered that building from pieces, whether you reconcile or not, is just not a good way to design.  Its not the pattern way.

 

The pattern way is about identifying those relationships among the conceptual entities to be represented within the problem space.  Ultimately it comes down to this:  Look at the big picture, and determine a situation out of that big picture in which a pattern applies.    The first phase is the define stage, where requirements and objectives should be identified and analyzed, and the second phase is where the conceptual model should emerge.  It can be these patterns that bring that conceptual model to life.

 

Incidentally, these two stages are represented in Borlands Application Lifecycle Management (ALM) process, which is depicted in Figure 3-1 below. 

 

 

Figure 3-1 - Borlands Application Lifecycle Management (ALM) Process

 

 

ALM provides a high level process that can be tailored to meet your specific development process for your organization and projects.  ALM is a flexible model that supports iterative and incremental development efforts (i.e., spiral development), as well as sequential development efforts (i.e., waterfall development), and development efforts that fall somewhere in between.   

 

Lets explore this process further in relation to the Define and Design stage, which is depicted in Figure 3-2.

 

Figure 3-2 - Requirements Driven Representation

 

 

3.1       Define - Conceptual Analysis

 

Before going off and designing and developing the individual pieces.  Look at the context of the problem as a whole; the Big Picture.  Understand the context of the problem being solved. This often begins with a simple statement of the problem or need.  Following this initial effort, you should then be able to add more detail.  The detail embodies and supports the necessary requirements  stating what needs to occur.  Stating what needs to occur then drives us toward identifying those relationships, which ultimately leads us to design.  However, the identification of those relationships, which is critical to the process, is referred to as conceptual analysis. 

 

Conceptual analysis involves understanding the objectives and requirements and what elements and activities might be needed to support them.  Unfortunately conceptual analysis is often missed during the development process.  

 

To better comprehend the conceptual analysis phase, lets look at an example, which we will leverage through out our exploration of design patterns.  Suppose we wish to build a simulation modeling the operations of an airport and the aircraft for which the airport serves.  We begin by identifying the major activities that a typical airport might support:

 

  • Flight Operations

7         Departures

7         Arrivals

7         Taxing

  • Baggage Service

7         Loading / Unloading

7         Baggage Claim

  • Ground Transportation Service

7         bus,

7         taxi,

7         limo,

7         rental cars

  • Food Service

7         Airport restaurants

7         Airline catering

  • Merchandise Sales

7         newspapers / books,

7         snacks,

7         medicine,

7         Souvenirs

  • Security

7         Passenger Checkpoint

7         Baggage Check

 

Typically we dive deeper to identify functional capabilities and external sources (or actors) required for airport operation simulation.  For instance we know that Air Traffic Control, Ground Crew, and Aircraft are needed to fulfill our Flight Operations.   Using UML, we can begin to represent that functionality and actors using Use Cases as depicted below.

 

 

Figure 3.1-1  Use Case of Flight Operations for supporting Arrivals

 

 

As you can see, this approach allows us to understand relationships, which can be communicated with other developers and stakeholders. In this picture we can see that Arrival support for aircraft include the Taxing activity.  The actors associated to supporting the arrival of the Aircraft is dictated by Airport Air Traffic Control, whereas the Ground Crew guides the Aircraft to its Gate during Taxing.  

 

Once we understand and agree upon the relationships among conceptual entities we can begin our Design with a sense of confidence that we will meet and/or exceed our objectives.

 

3.2       Design  Conceptual Model Representation via Design Patterns

 

The hurdles in reaching a conceptual model representation are typically in knowing how to capture the various conceptual models that represent the domain space, and, more importantly, knowing what to look for within the problem domain space in which a conceptual model should be engineered.  Ultimately what our concept model should reflect are the following items:

1           what the system will represent,

2           the assumptions limiting those representations, and

3           other capabilities needed to satisfy the users requirements.  

 

The first bullet identifies the need to represent structural elements needed of our design.  This is where structural design patterns can be applied and used. 

 

The second bullet identifies the creational limitations and capabilities upon those structural representations, which are needed for realistically modeling our system.  This is where conceptual design patterns can be applied and used.

 

Finally, the third bullet identifies the behavioral capabilities needed of the conceptual entities being represented within the problem space.   This is where behavioral design patterns can be applied and used.

 

Ultimately, the application of design patterns leads us to the ability and desire to create flexible and reusable classes and code modules.  A list of the common patterns used in software development, which are identified in the Gang of Four (GoF) book, is shown in the table below.

 

 

 Table 3.2 - Types of Patterns

 

Pattern Name

Type

Description

GoF Reference

Abstract Factory

Creational

Used to identify an interface for creating families of related or dependent objects without specifying their concrete classes.

87

Builder

Creational

Used to separate the construction of a complex object from its representation so that the same construction process can create different representations.

97

Factory Method

Creational

Used to identify an interface for creating an object, but having the subclasses be responsible for the instantiation of a class.

107

Prototype

Creational

Used to specify the kinds of objects that are to be created using a prototypical instance, and allow new objects to be created by copying this prototype.

117

Singleton

Creational

Used to ensure a class has only one instance, and to provide a global point of access to it.

127

Adaptor

Structural

Used to convert a class interface into another class interface. 

139

Bridge

Structural

Used to decouple an abstraction from its implementation so that the two can vary independently.

151

Composite

Structural

Used to compose objects into tree structures for representing part-whole hierarchies.

163

Decorator

Structural

Used to dynamically attach additional responsibilities to an object.  This is an alternative to subclasses.

175

Facade

Structural

Used to identify a unified, higher-level interface to connect to a set of interfaces in a subsystem.

185

Flyweight

Structural

Used to share a large volume of small objects efficiently.

195

Proxy
(Surrogate)

Structural

Used to provide a surrogate or placeholder for another object to control access to it.

207

Chain of Responsibility

Behavioral

Used to avoid coupling the sender of a request to its receiver by giving more than one object a chance to handle the request.

223

Command

Behavioral

Used to encapsulate a request as an object.

233

Interpreter

Behavioral

Used to define a grammar for simple languages, to represent sentences in that language, and to interpret those sentences.

243

Iterator
(Cursor)

Behavioral

Used to provide a way to access the elements of an aggregate object sequentially without exposing its underlying representation.

257

Mediator

Behavioral

Used to define an object that encapsulates how a set of objects interact.  Mediator promotes loose coupling by keeping objects from referring to each other explicitly, and it lets you vary their interaction independently.

273

Memento

Behavioral

Used to capture and externalize an objects internal state without violating encapsulation so that the object can be restored to this state later.

283

Observer

Behavioral

Used to define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.

293

State

Behavioral

Used to allow an object to alter its behavior when its internal state changes so that the object appears to change its class.

305

Strategy

Behavioral

Used to define a family of algorithms, encapsulate each one, and make them interchangeable. 

315

Template Method

Behavioral

Used to define a skeleton of an algorithm in operation, deferring some steps to subclasses. 

325

Visitor

Behavioral

Used to define a new operation to be performed on the elements of an object structure without changing the classes of the elements.

331

 

This is not an exhaustive list of patterns that can be used to represent the conceptual model.  Certainly it is possible to identify other types of patterns.  However, for our discussion, we will focus on some but not all of the GOF patterns identified in Table 3.2.  For those that we dont cover, additional resources are identified at the end of this article that you may choose to investigate. 

 

Note: be careful not to go straight into identifying solutions a pattern offers.  That aspect should be held off until later in the development process following the design phase when the conceptual model is well understood, and the relationships among conceptual entities have been identified.

 

In the next section well explore how we can begin to codify a pattern.

 

4          How do we Codify Patterns?

 

Patterns exist in the everyday real world.  We find instances of them just about everywhere we go.  For example, automated doors with sensors that open for us represent a pattern that we see whether we are at the grocery story, Wal-Mart, Best Buy, or a museum.  As another example, a traffic light serves as a conceptual entity involving an indirect relationship with automobiles and a direct relationship with a timer and perhaps a trigger plate as well.  This forms a pattern which we see instances of throughout the world.  They essentially all work the same.  Red light, cars stop.  Time elapses, the green light is engaged, cars move.  Time elapses, yellow light is spawned for a few seconds, cars speed up or slow down.  Red light is then engaged again.

 

After awhile, recognizing patterns becomes almost a second-hand instinct, but, beyond recognizing them, the key is in knowing how to codify them so that they can be reused.  Specifically we must ask, how do we document a pattern in such a way that it is understood and it can be reused for other purposes that require a similar set of activities and among similar conceptual entities?

 

In the transition from understanding requirements and the design, its important to separate and leave out the details that borderline on implementation from the solution that will be represented by patterns.   Incidentally, this mindset of separating the interface from the implementation is embodied in the Bridge Pattern strategy.

 

4.1       Begin with an Abstract Description

 

The Gang of Four recognized that patterns, as practical as they were for software development, would not be useful unless there was a way to document them.  At a high level, a pattern should provide an abstract description of a design problem and how a general arrangement of elements solves it. [GoF]    In our examples, we will provide an abstract description as it relates to our conceptual model.  Using narrative text is a key mechanism for reflecting our understanding of the requirements and objectives, and how the conceptual model, based on patterns, might be used to fulfill those objectives.

 

4.2       Use UML (and Together.)

 

In addition to an abstract description, UML provides a terrific diagramming mechanism for visualizing patterns.   There are several UML diagrams that we can use to help paint our patterns including class diagrams and sequence diagrams.  We will use Borlands Together software package to build UML diagrams that embody our pattern examples.  You will find that Patterns make more sense when you can see them visually with UML.

 

Before we dive in to creating our examples, however, lets take some time to review some of the more relevant UML diagrams that help us paint our patterns.  The most common UML diagram is the class diagram.  It is used to diagram abstract and concrete classes, and provides the basis for defining interfaces.  Consider the following c# class in Listing 4.2.

 

Listing 4.2 -   Passenger Class Displayed in C#

 

 

      public class Passenger  

      {

            private string Name;

            private string Destination;

            private int FlightNum;

            private string Seat;

            // ----

 

            public Passenger (string name, string dstn, int flight, string seat)

            {

                  Name = name

                        Destination = dstn;

                  FlightNum = flight;

                  Seat = seat;

            }

 

            public bool BoardPlane(int flight)

            {

                  FlightNum = flight;

                  return true;

            }

 

            public bool TakeSeat(string seat)

            {

                  Seat = seat;

                  return true;

            }

     

            public bool GetSeat()

            {

                  Seat = seat;

                  return true;

            }

      }

 

 

      

 This class can be represented visually in UML as follows.

 

 

Figure 4.2-1 -   Passenger Class Displayed using a UML Class Diagram

 

As shown in this example, a single UML class can be broken into multiple parts or partitions, which are referred to as compartments in Together.  The top partition, usually in bold text, identifies the class name, the second partition lists the attributes (or fields) of the class, and the third partition identifies the behaviors (or methods) of the class. Some tools, like Together, offer a fourth partition to identify properties of the class.   Together also allows you to add other class elements such as indexers, methods and subclasses.  You may be curious about the symbology used in the UML class diagram before the attributes and behaviors.  The symbols used for the visibility tag is identified in Table 4.2-1.  Note: Borland VCL developers should use the public symbol for identifying published attributes (members). 

 

Table 4.2.-1  Visibility Symbols for Attributes and Operations

 

Symbol

Visibility

+

Public

#

Protected

-

Private

 

protected internal

 

internal

 

For some UML tools, its not uncommon to leave off the visibility, type and default values if the attribute name itself provides enough description to discern the intent.

 

In order to understand relationships of class that can be depicted, let us further expand our class example to include an Aircraft class.  This is depicted in Figure 4.2-2.

 

 

Figure 4.2-2 -   Passenger Class Associated with an Aircraft

 

 

Here you can see that the Aircraft contains multiple passengers through the association link between these two classes whose multiplicity is identified on the passenger class. 

 

At this point weve kept things real simple with our class example.  Furthermore, weve only scratched the surface regarding the capability UML provides.  In addition to class diagrams, there are 9 other UML diagrams.  As we progress through some of the pattern examples the UML views should become more clear.

 

Also, for each pattern used in our examples that follow, we will use the following template (Table 4.2-2), leveraging sacred text from the GoF book, which will provide the foundational elements needed to understand the specific pattern.

 

Table 4.2‑2 - Template for Patterns

 

Item

Description

Example

Name

Specific pattern

How example applies.  Specifically relationship of example elements to abstract participants associated to pattern and reflect in UML class diagram.

Intent

Purpose of the pattern

Participants

The conceptual entities involved in supporting the pattern

 

 

The use of this table will be used in conjunction with an abstract UML diagram, which will help you visualize and understand the specific pattern of interest.

 

5          Patterns by Example

 

Now that we have identified what patterns are about and that we can begin to document them using narrative text and UML class diagrams, lets look at some practical examples leveraging from the example airport scenario, which explore the application of some of the more prevalent patterns. 

 

5.1       The Fagade Pattern

 

The Fagade Pattern is used to identify a unified, higher-level interface to connect to a set of interfaces in a subsystem.    For example, in our airport scenario, e-ticket kiosks provide passengers essentially a fagade to the more complex reservation and ticketing subsystem.  Specifically our e-ticket machine is used to issue a boarding pass, querying the number of bags to check, and taking care of seating. Certainly, the underlying reservation and ticketing system has much more capability.  This fagade is intended to make it very easy for passengers to check in.  However, the agent at the ticket counter has much more control and access to the reservation subsystem responsible for passenger ticketing.  The agent requires extensive training of the system to manipulate and manage the ticketing (or re-ticketing) of passengers.  Whereas for an e-ticket kiosk, the learning curve for travelers must be quick and it must be protected. This is a perfect case for the application of a fagade. 

 

As another example, which is outside of the scope of our airport example, consider a 3-D graphics engine.  Most game developers choose to utilize an existing graphics engine rather than reinventing and creating their own (although many have certainly tried).  The reason is simple, it is cost prohibitive to go off and create a brand new graphics engine when there are so many other aspects of the development that need to be accomplished for the production of the game.  Invariably these graphics engines provide an Application Programmer Interface (API).  This API provides a fagade to the underlying 3-D graphics engine, which the game developer cares to know very little about. 

 

One of the drawbacks of the Fagade interface is that it is not complete; meaning youre not going to have all the functionality that the subsystem has to offer.  It can be said, however, that by limiting full functionality the Fagade provides a degree protection.  Furthermore, a key benefit in using a Fagade interface is that it simplifies usability.  Additionally, a fagade can help manage multiple objects thereby reducing the number of objects that a client object would typically have to deal with.  Essentially a Fagade pattern helps encapsulate the system.  Theoretically, the system can change or be updated without impacting the fagade interface.

 

The illustration below provides the default Together view for the Fagade Pattern.  This is followed by a table describing each participant associate with generic labeled class in the diagram.

 

 

 

 

 

Item

Description

Example

Name

Fagade Pattern

Client = traveler

Fagade = E-Ticket Kiosk

Subsystem = complex reservation and ticketing subsystem

Intent

Used to provide a unified interface to a set of interfaces in a subsystem.

 

Facade defines a higher-level interface that makes the subsystem easier to use.

Participants

Facade knows which subsystem classes are responsible for a request.
delegates client requests to appropriate subsystem objects.

 

Subsystem implements subsystem functionality.
handle work assigned by the Facade object.
have no knowledge of the facade; that is, they keep no references to it.

 

 In our example the Fagade is the E-Ticket machine, whereas the Subsystem is the airline Reservation and Ticketing system.  

 

5.2       The Adapter Pattern

 

The Adapter Pattern is used to convert a class interface into another class interface expected by a client.  Let us suppose the automated pilot control system (APCS) of the majority of airplanes served by our airport requires positional coordinates in latitude (minutes), longitude (minutes), ground clearance (meters), and air speed at (meters/second).  However, our navigation system is GPS-based, and provides information latitude (decimal degrees), longitude (decimal degrees), elevation (feet above sea level), and ground speed (knots).   The GPS navigation system has the information that the APCS needs for it to perform its task, but, from the perspective of the APCS, the format of the information is wrong.  Heres where the Adapter pattern can be applied, which converts the GPS data to a format comprehensible to the APCS.

 

The illustration below provides the default Together view for the Adapter Pattern.  This is followed by a table describing each participant involved in supporting the Adapter Pattern, which is reflected as a generic class in the UML diagram.

 

 

 

 

 

Item

Description

Example

Name

Adapter Pattern

Client = automated pilot control system (APCS)

Target = domain-specific interface for APCS

Adaptee = existing GPS navigation system

Adapter = adapts the interface of the GPS navigation system to the Target interface required for use by the APCS

 

Intent

Used to convert the interface of a class into another interface, which clients expect.

 

An Adapter lets classes work together that couldn't otherwise because of incompatible interfaces.

Participants

Target defines the domain-specific interface that Client uses.

Adaptee defines an existing interface that needs adapting.

Adapter adapts the interface of Adaptee to the Target interface.

 

 

In the UML diagram above, the Target defines the domain-specific interface that the APCS uses.   The Adaptee defines the existing GPS navigation system interface that needs adapting.  Therefore, the Adapter, adapts the interface of the GPS navigation system to the Target interface required for use by the APCS.

 

5.3       The Bridge Pattern

 

The Bridge Pattern is designed to separate a classs interface from its implementation allowing you to vary or replace the implementation without changing the client code.  It is used to decouple an abstraction from its implementation so that the two can vary independently.  Essentially the bridge pattern is about separating the interface from the implementation.  What it is you are trying to represent is independent from how it is to be represented.

 

Lets go back to our automated pilot control system (APCS) for a moment.    Let us suppose that, for the airplanes that service our airport, the navigation system used by APCS may vary.  Modern planes may use GPS-based navigation systems, in which heading, position and altitude are determined quite accurately by satellite, whereas other older planes may use either a VHF Omnidirectional Range (VOR) navigation system or even, the more antiquated Automated Direction Finder (ADF) navigations system, in which triangulation of radial signals among nearby beacon towers located on the ground or at sea are used to determine a planes heading, position and altitude.   Ultimately, for the APCS, the navigation system interface needs to be the same.  However, the actual systems employed may be different.  This is where the Bridge Pattern comes into play.

 

 The illustration below provides the default Together view for the Bridge Pattern.  This is followed by a table describing each participant involved in supporting the Bridge Pattern, which is reflected as a generic class in the UML diagram.

 

 

 

 

Item

Description

Example

Name

Bridge Pattern

Abstraction  APCS interface

Implementor - General avionic representation for Navigation Data

ConcreteImplementor -  GPS, VOR, ADF systems

Intent

Used to decouple an abstraction from its implementation so that the two can vary independently.

Participants and Collaborators

Abstraction defines the abstraction's interface.
maintains a reference to an object of type Implementor.

Implementor defines the interface for implementation classes. This interface doesn't have to correspond exactly to Abstraction's interface; in fact the two interfaces can be quite different. Typically the Implementor interface provides only primitive operations, and Abstraction defines higher-level operations based on these primitives.

ConcreteImplementor implements the Implementor interface and defines its concrete implementation.

 

In our example above, the Abstraction represents the needed information to represent the interface for our navigational information.  This abstraction maintains a reference to an object of type Implementor, which is the navigational system. Implementor defines the specific interface for the implementation class.   The ConcreteImplementor implements the Implementor interface and defines a specific concrete implementation representing one of the following:

 

  • GPS navigation system
  • VOR navigation system
  • ADF navigation system

 

 

5.4       The Abstract Factory Pattern

 

The Abstract Factory Pattern is used to identify an interface for creating families of related or dependent objects without specifying their concrete classes. [GOF]

 

In our airport example, we have a need to handle various types of ground transportation services.  If we were to create an abstract factory to support our ground transportation we can identify the related types of transportation provided to travelers.  This might include a bus service, taxi service, limo service or rental car service.    

 

The illustration below provides the default Together view for the Abstract Factory Pattern.  This is followed by a table describing each participant involved in supporting the Abstract Factory Pattern, which is reflected as a generic class in the UML diagram.

 

 

 

 

 

Item

Description

Example

Name

Abstract Factory Pattern

AbstractFactory  - Ground Transportation Service Counter

ConcreteFactory  -  Service phone or touch screen used for requesting bus, limo, taxi or rental car

AbstractProduct  - Generic representation of a Transport service  for loading., boarding and riding, (might consider use of Decorator Pattern to add driving capability for rental car)

ConcreteProduct  - Bus, Rental Car, Taxi, Limo

Client  Traveler with need to for Ground Transportation

 

Intent

Used to provide an interface for creating families of related or dependent objects without specifying their concrete classes.

Participants and Collaborators

AbstractFactory  - declares an interface for operations that create abstract product objects.

ConcreteFactory  - implements the operations to create concrete product objects.

AbstractProduct  - declares an interface for a type of product object.

ConcreteProduct  - defines a product object to be created by the corresponding concrete factory; also implements the AbstractProduct interface.

Client - uses only interfaces declared by AbstractFactory and AbstractProduct classes

 

 

 

5.5       The Strategy Pattern

 

The Strategy Pattern allows different algorithms to be used depending on the context in which they occur.  The selection of an algorithm that needs to be applied depends upon the client making the request or the data being acted upon.  [It] separates the selection of algorithm from the implementation of the algorithm.  [It] allows for the selection to be made based upon context. 

 

For our airport simulation, let us consider the need to monitor and manage air traffic.   It is our airports responsibility to provide Air Traffic Control (ATC) in order to ensure safe, orderly and expeditious flow of air traffic.  One of the many jobs of the air traffic controller is to provide separation between landing and departing aircraft.  Air traffic controllers must be familiar with the aircraft identification and positions of the aircraft under their control, aircraft types and speeds, and the location of navigational aids and landmarks in the area.  He must ensure that inbound planes arrive within the proper window of time, and are clear of any other air traffic, whether in the air or on the run-way.  Thus, part of an air traffic controllers responsibility is to determine where an airplane will be, based it on its current speed, pitch and heading, at any point in time.  The method for an air traffic controller to dead reckon position of an aircraft may vary widely.  It is in this situation, where the varying mechanisms for determining potential aircraft position by air traffic controller can be supported using the Strategy pattern.  In our example, this pattern might be applied to select a dead-reckoning algorithm based on factors such as weather, the number of aircraft in the air or on the ground, and an airports acceptance rate, which is dictated by the FAA.

 

The illustration below provides the default Together view for the Strategy Pattern.  This is followed by a table describing each participant involved in supporting the Strategy Pattern, which is reflected as a generic class in the UML diagram.

 

 

 

 

 

 

 

Item

Description

 Example

Name

Strategy Pattern

Strategy  Position Calculation interface

ConcreteStrategy  Specific Dead Reckoning (DR) function (one for each DR algorithm)

Context - maintains a reference to the Position Calculation interface.

Client  Air Traffic Controller

Intent

Used to define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it.

Participants and Collaborators

Strategy
declares an interface common to all supported algorithms. Context uses this interface to call the algorithm defined by a ConcreteStrategy.

ConcreteStrategy
implements the algorithm using the Strategy interface.

Context
is configured with a ConcreteStrategy object.
maintains a reference to a Strategy object.
may define an interface that lets Strategy access its data.

 

 

 

 

5.6       The Composite Pattern

 

The Composite Pattern is used to form a collection of objects.  There are numerous examples of composites.  For instance, in our airport scenario, each airplane that services our virtual airport is made of a collection of subsystems such as the landing gear system, avionics / navigation system, a fuel system, and the physical flight frame, which affects its flight.  By themselves any one of these subsystems may have little value to us, but collectively they are needed to form and represent our airplane.  As a looser example, one which we might want a model for the security inspection of luggage, we could use a Composite Pattern to represent the contents within a suitcase, or the collection of suitcases within the cargo hold of an airplane.

 

The illustration below provides the default Together view for the Composite Pattern.  This is followed by a table describing each participant involved in supporting the Composite Pattern, which is reflected as a generic class in the UML diagram.

 

 

 

Item

Description

Example

Name

Composite Pattern

Component  Airplane Subsystem

Leaf  Avionics, Landing Gear, Frame

Composite  Airplane)

Intent

Used to compose objects into tree structures to represent part-whole hierarchies. Composite lets clients treat individual objects and compositions of objects uniformly.

Participants and Collaborators

Component

7         declares the interface for objects in the composition.

7         implements default behavior for the interface common to all classes, as appropriate.

7         declares an interface for accessing and managing its child components.

7         (optional) defines an interface for accessing a component's parent in the recursive structure, and implements it if that's appropriate.

Leaf

7         represents leaf objects in the composition.

7         A leaf has no children.

7         defines behavior for primitive objects in the composition.

Composite

7         defines behavior for components having children.

7         stores child components.

7         implements child-related operations in the Component interface.

 

 

5.7       The Flyweight Pattern

 

The Flyweight pattern can be used to help manage large numbers of class instances (i.e. entities) within our system.  By identifying the common attributes of the classes representing the objects (or entities) within a system, a common class can be defined and, where there are any differences in attributes among the various classes, these can be maintained as extrinsic data passed in as arguments. For instance, in our airport system that we are modeling, our Air Traffic Control Center needs to monitor the collection of aircraft within the airports region airspace.  The collection of aircraft can be aggregated into a composite group, which could be used to optimize the performance of our system.  This is where the flyweight pattern can be applied.

 

The illustration below provides the default Together view for the Flyweight Pattern.  This is followed by a table describing each participant involved in supporting the Flyweight Pattern, which is reflected as a generic class in the UML diagram.

 

 

 

 

Item

Description

Example

Name

Flyweight Pattern

Flyweight  Aggregated entity group (of aircraft)

ConcreteFlyweight  - Common Entity information (intrinsic to all air tack objects)

UnsharedConcreteFlyweight  - Unique Entity information (extrinsic air track elements).

FlyweightFactory - creates and manages aggregates of Air Tracks (airplanes, helicopters, blimps).

Client  Plan View Display (used to display air tracks)

Intent

A sharing principle used to support large numbers of fine-grained objects efficiently.

Participants and Collaborators

Flyweight

7         declares an interface through which flyweights can receive and act on extrinsic state.

ConcreteFlyweight

7         implements the Flyweight interface and adds storage for intrinsic state, if any.

7         must be sharable.

7         Any state it stores must be intrinsic; that is, it must be independent of the ConcreteFlyweight object's context.

UnsharedConcreteFlyweight

7         not all Flyweight subclasses need to be shared.

7         The Flyweight interface enables sharing; it doesn't enforce it.

7         It's common for UnsharedConcreteFlyweight objects to have ConcreteFlyweight objects as children at some level in the flyweight object structure.

FlyweightFactory

7         creates and manages flyweight objects.

7         ensures that flyweights are shared properly.

7         When a client requests a flyweight, the FlyweightFactory object supplies an existing instance or creates one, if none exists.

Client

7         Maintains a reference to flyweight(s)

7         Computes or stores the extrinsic state of flyweight(s).

 

 

5.8       Chain of Responsibility

 

The Chain of Responsibility pattern is used to ensure a request from an object can be fulfilled by at least one other object among a chain. This is accomplished by associating a tree of objects, which is identified as the chain, with each object potentially given the opportunity to field an object request.  The GoF describes the chain of responsibility as more than one object identified as a receiver with each [sequentially] given a chance to handle the request.  Essentially, the first object in the chain fields the request and if its unable to support the request it will pass it on to the next object in the chain. This will repeat until an object in the chain is able to field and support the request.  The requesting object is ignorant as to who will ultimately handle the request.   Therefore such an object that fulfills the request is identified as an implicit receiver. 

 

Suppose in our airport scenario, we may have tens of thousands of travelers passing through in a single day.  Consider that each traveler either is departing or arriving.  For those departing their desire is obviously to check their bags, be ticketed, and board their planes.  However, in order for travelers to board their planes they need to arrive at the gate on time.   But before they can arrive at the gate they need to go through an airport security screening checkpoint.  It is at this checkpoint, where we can identify a model depicting a chain of responsibility for members of the Transportation Security Administration (TSA).  The request for the traveler is to be allowed to proceed to his gate.  But the TSA security officer who ultimately has final authority in fulfilling the travelers request may be long down the chain of responsibility. 

 

On busy days, we might see a TSA security greeter, who notifies travelers to be sure to have their boarding pass and ID ready and then directs passengers to the entry point of the queuing maze.  The passenger is then greeted by a security agent, who cross checks ticketed travelers with their ID.  If a passenger has a boarding pass not issued for the date of travel and/or the ID does not match, then the traveler is jettisoned from the line or potentially passed on to another TSA agent for questioning.  Otherwise, the traveler is told that he may proceed toward the baggage scanner and walk-through metal detector.  At the conveyer belt for the baggage scanner the passenger may empty his bag of his laptop, remove his shoes and place other items in a tray which is placed on the belt along with items such as a carry-on-baggage and an outer jacket.  These items are fed through an x-ray security scanner where screeners analyze the contents inside the material.  While this is in motion, the traveler is instructed by another agent to proceed through a walk-through metal detector which scans for metallic items that may be on the person. If the walk-through metal detector alarm rings, the agent may ask the traveler to repeat the procedure, or to step to a specific area for a secondary fully-body screening, which is performed by another agent using a manual metal scan wand.  Meanwhile, if the baggage screener identifies a suspicious item during the x-ray view, he/she may alert another agent down the chain, who will be responsible for visibly scanning the suspicious baggage.  Providing the traveler and his baggage make it through all these stages of the security checkpoint, the traveler will be permitted to proceed to the gate.

 

 

The illustration below provides the default Together view for the Chain of Responsibility Pattern.  This is followed by a table describing each participant involved in supporting the Chain of Responsibility Pattern, which is reflected as a generic class in the UML diagram.

 

 

 

 

 

 

 

Item

Description

Example

Name

Chain of Responsibility

Handler  TSA Security Agent (generic representation for staff members at a security checkpoint).

 

ConcreteHandler  We identified several: 

  • Security Greeter,
  • Boarding Pass Checker,
  • Carry-on Baggage X-Ray Screener,
  • Hands-on Baggage Checker,
  • Walk-through metal detector Screener,
  • Pat-down Agent.

Intent

Used to avoid coupling the sender of a request to its receiver by giving more than one object a chance to handle the request.  Chain the receiving objects and pass the request along the chain until an object handles it.

Participants and Collaborators

Handler - defines an interface for handling requests; (optional) implements the successor link.

 

ConcreteHandler - handles requests it is responsible for.
can access its successor; if the ConcreteHandler can handle the request, it does so; otherwise it forwards the request to its successor.

 

Client  initiates the request to ConcreteHandler object on the chain.

 

 

 

  

6          What to do with Patterns?

 

The intent of going through the examples in the last section is help us better recognize and codify patterns during the Define and Design stage of development -- before we actually go to code.  The questions you might be asking now are, What do we do with them? How do we use them to build code? And finally, How do we make them available for others to use? 

 

These are all good questions.  As an aide, I have collected the GoF applicability statements associated to each Pattern as well as any related patterns and populated Table 6-1.  Examination of the column identified when to use a pattern should begin to shed some light on how to apply them thereby answering our first question.  As additional aide, the third column identifies related patterns including relevant descriptions as to how those are applied.

  

 

Table 6-1  Pattern Applicability

 

Pattern Type

When to Use Pattern

Related Patterns

Abstract Factory

When a system should be independent of how its products are created, composed, and represented.

 

When a system should be configured with one of multiple families of products.

 

When a family of related product objects is designed to be used together, and you need to enforce this constraint.

 

When you want to provide a class library of products, and you want to reveal just their interfaces, not their implementations.

Can be implemented with FactoryMethod or Prototype.

 

A concrete factory is typically a Singleton.

 

 

Builder

When the algorithm for creating a complex object should be independent of the parts that make up the object and how theyre assembled

 

When the construction process must allow different representations for the object thats constructed.

Similar to Abstract Factory

 

Composite is often built by Builder

Factory Method

When a class cant anticipate the class of objects it must create.

 

When a class wants its subclasses to specify the objects it creates.

 

When classes delegate responsibility to one of several helper subclasses, and you want to localize the knowledge of which helper subclass is the delegate.

Abstract Factory is implemented with Factory Methods

 

Typically Called within Template Methods

Prototype

When a system should be independent of how its products are created, composed and represented.

 

When the classes to instantiate are specified at run-time, for example, by dynamic loading

 

To avoid building a class hierarchy of factories that parallels the class hierarchy of products

 

When instances of a class can have one of only a few different combinations of state.

Similar to Abstract Factory, but can be used together

 

Heavy use of Composite and Decorator patterns can benefit from Prototypes

Singleton

When there must be exactly one instance of a class, and it must be accessible to clients from a well-known access point.

 

When the sole instance should be extensible by subclassing, and clients should be able to use an extended instance without modifying the code.

Abstract Factory

 

Builder

 

Prototype

Adapter

When you want to use an existing class, and its interface does not match the one you need.

 

When you want to create a reusable class that cooperates with unrelated or unforeseen classes (classes with incompatible interfaces)

 

When you need to use several existing subclasses, but it may be impractical to adapt their interface by subclassing every one. (referred to as an Object Adapter).

Bridge (separates interface, where as Adapter changes interface)

 

Decorator

 

Proxy

Bridge

When you want to avoid a permanent binding between an abstraction and its implementation (for instance when the implementation must be selected/switched at run-time).

 

When changes in the implementation of an abstraction should have no impact on clients (their code does not have to be recompiled)

 

When you want to hide implementation details from clients

 

When you want to improve extensibility of the abstraction and implementor hierarchies independently.

Abstract Factory can be used to create/configure a Bridge

 

Adapter

Composite

When you want to represent part-whole hierarchies of objects

 

When you want clients to be able to ignore the difference between compositions of objects and individual objects.

Component-parent link can be used for a Chain of Responsibility

 

Decorator often used with Composite (uses common parent class)

 

Flyweight used for sharing components

 

Iterator used to traverse Composites

 

Visitor

Decorator

To add responsibilities to individual objects dynamically and transparently  without affecting other objects.

 

For withdrawing responsibilities

 

When extension by subclassing is impractical. (Either an unmanageable set of subclasses would result or a class definition is hidden / unavailable for subclassing.)

Adapter

 

Composite

 

Strategy

Fagade

When you want to provide a simple interface to a complex subsystem.

 

When you want to shield clients from subsystem components, allowing you to

  • reduce the number of objects that clients deal with and
  • make the subsystem easier to use.

 

When you want to decouple subsystem and its clients allowing you to vary (swap out) the components of the subsystem without affecting its clients.

Abstract Factory can be used with Fagade

 

Mediator

 

Fagade objects are often Singletons

Flyweight

When an application uses a large number of objects; and

 

When storage / bandwidth cost is high because of quantity of objects; and

 

When most object states can be made extrinsic; and

 

When many groups of objects can be replaced by relatively few shared objects once extrinsic state is removed; and

 

When an application/network doesnt depend on object identity (it can handle aggregations)

Often combined with the Composite (for aggregation)

 

Recommended to implement State and Strategy objects as flyweights.

Proxy

(Surrogate)

When there is a need for a more versatile or sophisticated reference to an object than a simple pointer.

Adapter

 

Decorator

Chain of Responsibility

When more than one object may handle a request, and the handler isnt immediately known

 

When you want to issue a request to one of several objects without specifying the receiver explicitly

 

When the set of objects that can handle a request should be specified dynamically.

Often applied in conjunction with Composite

Command

When you want to parameterize objects by an action to perform.

 

When you want to specify, queue, and execute requests at different times.

 

When you want to support an undo like capability.

Composite can be used to implement macro Commands

 

Memento can keep state of a Command for supporting an undo operation.

 

Can act as a Prototype.

Interpreter

When there is language (such as meta-data) to interpret.

 

When there is language to extend.

Composite

 

Flyweight

 

Iterator used to traverse the Interpreter structure

 

Visitor

Iterator
(Cursor)

To access an aggregate objects contents without exposing its internal representation.

 

To support multiple traversals of aggregate objects.

 

To provide a uniform interface for traversing different aggregate structures (to support polymorphic iteration).

Applied to recursive structures such as Composites

 

Factory Method to instantiate an Iterator subclass

 

Often used in conjunction with Memento (to capture the state of an iteration)

Mediator

When a set of objects communicate in well-defined but complex ways.  (interdependencies are unstructured and difficult to understand).

 

When reusing an object is difficult because it refers to and communicates with many other objects.

 

When a behavior thats distributable between several classes would be customizable without a lot of subclassing.

Fagade

 

Observer used by collogues to communicate with Mediator

Memento

When an objects state must be saved so that it can be restored to that state later.

 

When a direct interface to obtaining the state would expose implementation details and break the objects encapsulation.

Command may use mementos to maintain state for undo operations

 

Iterator

Observer

When an abstraction has two aspects; one dependent on the other.  Encapsulating these aspects in separate objects lets you vary and reuse them independently.

 

When a change to one object requires changing others, and it is unknown how many objects need to be changed.

 

When an object should be able to notify other objects without making assumptions about who these objects are.  Used to keep objects from being tightly coupled.

Mediator

 

Singleton

State

When operational conditions and/or an objects behavior depend on an objects state.

Flyweight explains when and how State objects can be shared

 

State objects are often Singletons

Strategy

When many related classes differ only in their behavior.

 

When different variants of an algorithm are needed.

 

When an algorithm uses data that clients shouldnt know about.

Strategy objects make good Flyweights

Template Method

To implement the invariant parts of an algorithm once and leave it up to subclasses to implement the variable behavior.

 

When common behavior among subclasses should be factored and localized in a common class to avoid code duplication. 

 

To control subclass extensions.

Factory Methods are often called by Template Methods.

 

Strategy

Visitor

When an object structure contains many classes of objects with differing interfaces, and the desire is to perform operations on these objects that depend on their concrete classes.

 

When many distinct and unrelated operations need to be performed on objects in an object structure, and the desire is to avoid polluting their classes with these operations.

 

When the classes defining the object structure rarely change, but the desire is to define new operations over the structure.

Visitors can be used to apply an operation over an object structure defined by the Composite pattern.

 

Visitor can be applied to perform the interpretation required of an Interpreter

 

 

 

So now we ask, How do we use these patterns to build code?   Well one way is using a UML tool like Together, which provides some automation in taking a pattern and making legitimate code out of it.  In fact, one of the great things about using a tool like Together is that you can easily generate code from the UML model and toggle between the visual UML diagram and the C# or Java code for this class.  Any changes made to the UML can be reflected in the code through synchronization.  Likewise, any changes made to the code can also be reflected in the UML class diagram. It goes two ways.

 

Together also provides direct support for incorporating patterns, including providing a library of the GoF patterns that you can apply to a class diagram and gives you the opportunity to save new patterns, which we will explore next.  However, even without automation from a tool like Together, UML (and any related UML descriptions) can be used to provide the blueprint of our conceptual model needed for developers to implement code, thereby satisfying the objectives identified in the Define phase.

 

The last question was, How do we make them available for others to use?  The key to reuse is making patterns available for use in the future  and for others.  This can be accomplished several ways.  Within a tool like Together, we can identify a pattern, build it using UML and save it as specific pattern that can be called up again later.  This process is illustrated in Figure 6-1 and Figure 6-2, which takes a sequence diagram representing the common activities associated for a weapons fire engagement.  

 

 

 

Figure 6-1  Saving a Weapons-Fire Engagement Pattern in Together. Edition for Visual Studio

 

 

 

Figure 6-2 Together. Edition for Visual Studio - Create Pattern Wizard 

 

It should be noted that the entity for the firing platform illustrated in the sequence diagram of Figure 6-1 could be a tank, an aircraft, a submarine, or even a soldier. Likewise, the entity for the target platform could be any number of types of entities as well.  This approach satisfies the Bridge pattern strategy to maintain a deep enough level of abstraction to our conceptual model in which we could apply any number of types of implementations to fulfill this interface.  This focus on abstraction is important in ensuring reuse.

 

There are other methods to document patterns as well, including XMI, which is an XML-based syntax for represent UML diagrams.  Outside of UML, I also recommend Use Case Templates, devised by Alistair Cockburn.  Within the simulation community, another method for codifying patterns of interplay, such as the Weapons-Fire Engagement, is the use of Base Object Models (visit www.boms.info for more information). 

 

 

7          Summary

 

In this paper, we have briefly looked at the concept of patterns for improving software development.  This includes sharing how to recognize patterns early in the development process during the define and design stages.  Weve also looked at specific examples for codifying patterns including the use of UML diagrams (and Borland Together.).  Finally, we explored how to begin to benefit from the patterns that you and others apply and create.  

 

Shalloway and Trott state that, Patterns give you a higher-level perspective on the problem and on the process of design and object orientation.  This frees you from the tyranny of dealing with the details too early. [DPE  80].

 

There are three suggestions that the GoF highlight in applying patterns that can help you attain this higher-level perspective:

1           Program to an interface, not an implementation. (GoF - p 18)

2           Favor object composition over class inheritance. (GoF - p. 20)

3           Consider what should be variable in your design and encapsulate the concept that varies. (GoF - p. 29)

 

Over time, youll find that the application of patterns will change your perspective as a developer.  Youll find that software development isnt driven by defining intricate classes and subclasses with high levels of inheritance, but by recognizing those things that are related and that are used with some frequency, which can be abstracted into a pattern.  It may take some time to grasp the pattern concept, but, if you take the initiative, it will come to you and youll soon find a deeper level of satisfaction in the designs and software that you produce.

  

 

References

 

Alexander, C., Ishikawa, S., Silverstein, M., A Pattern Language: Towns/Buildings/Construction, Oxford University Press, 1977

 

Alexander, C., Ishikawa, S., Silverstein, M., The Timeless Way of Building, Oxford University Press, 1979

 

Cockburn, A., Writing Effective Use Cases, Addison-Wesley, 2001.

 

Fowler, M., Analysis Patterns: Reusable Object Models, Addison Wesley, 1997.

 

Fowler, M, UML Distilled Third Edition: A Brief Guide to the Standard Object Modeling Language, Addison Wesley, 2004.

 

Gamma, E., Helm, R., Johson, R., Vlissides, J., Design Patterns Elements of Reusable Object-Oriented Software, Addison-Wesley, 1995.

 

Shalloway, A., Trott, J., Design Patterns Explained:  A New Perspective on Object-Oriented Design, Addison-Wesley, 2002.

 

 

Biography

 

Paul Gustavson is Chief Scientist and cofounder of SimVentions, Inc and supports a wide variety of software development, modeling and simulation, and Web technology efforts.  An accomplished C++ and Delphi developer, Paul has been a long time user of Borland's developer tools starting with Turbo Pascal in 1983.  He has written and presented numerous publications on simulation interoperability and software development, and is a co-author of "C++Builder 6 Developer's Guide", a contributing author to "C++Builder 5 Developer's Guide", and the technical editor for SAMS Teach Yourself UML (2nd Edition).  Paul lives in Virginia with his wife and two boys.

 

 

 

  Latest Comments  View All Add New RSS ATOM

Move mouse over comment to see the full text

Server Response from: SC4