[ 1 ] [ 2 ] [ 3 ] [ 4 ] [ 5 ] [ 6 ]

Review of Class Design“Is a” diagrams (Inheritance)

 “Has a” diagrams (Composition)

Design Patterns

Identifying problem patterns

The problems we encounter in development fall into repeating patterns.  When we can identify the patterns in the problems we have we can apply design patterns to solve those problems.

Using design patterns

You will see in our discussion of design patterns that often there can be patterns found inside of patterns.  There are also situations where a particular design may be classified as differing patterns depending on exactly how you look at the design.  This should not be seen as a complication of design patterns but rather as a result of the high level of abstraction that at which design patterns reside.

Design patterns are abstract that is they have very little detail included in them that refers to implementation.  Design patterns are more like a block diagram of an approach to a problem than a prescription to a solution for a problem.

The following sections discuss a few specific design patterns with some examples of their application.

Singleton

Gamma and Helms describe the intent of the singleton pattern as, “Ensure a class has one instance, and provide a global point of access to it.”

Let’s look at an application design problem that could be solved by applying the singleton design pattern.  We have an application with many forms any of which may require a toolbar.  We want one toolbar only to ever exist.  If multiple forms are open we want them to share a single toolbar.

How can we accomplish this?  In our example project named Patterns we have done this very thing.

If you look at the Application Manager class you will see a method named LaunchToolbar.  This method will create a toolbar for a form that requests one.  The key that makes this an implementation of the singleton pattern is the fact that no matter how many forms get created that request a toolbar there only ever be one toolbar.  The form’s access to that toolbar is through the Application Manager class’ oToolbar property.

Interestingly, Gamma and Helms go on to say the following about the singleton pattern, “The pattern makes it easy to change your mind and allow more than one instance of the Singleton class.”  In our example the forms collection along with the oForm property of the AppMgr demonstrates this concept.  The oForm property is very similar to the oToolbar property, except that there can be multiple forms open.  The Application Manager is the single reference point for the Toolbar to reach the currently active form by using the oForm property.

Bridge

There are times when both the interface and the implementation of a process must be able to vary independently.  When a particular interface may have multiple implementations the common method to use in designing this is inheritance.

The figure above shows an inheritance tree for a form class that has printing capabilities.  The interface for printing is the Print method of the form class.  The implementation may vary from one form to another as the print outs will look different.

Introduce to this design the issue of differing printing devices like laser printer, ink jet printer, and fax and you can see that this inheritance design is not going to meet the requirements.  Enter the bridge pattern.

Another example of a bridge pattern will be seen later when we see the disconnected data access design of the multi-tier model.

Decorator

Often called a wrapper, the decorator pattern is used to add functionality to an object dynamically.  The following figure shows part of our multi-tier model that will be expanded later.  The part shown is the business object design.  One of the responsibilities of the business object is to move data to and from the data access object.  The mechanism and structure of the data stream that moves between these two objects can vary.  We use a decorator, the Stream Processor, to allow the business object to handle whatever type of data stream it receives.

Mediator

A mediator loosens the coupling between other objects by preventing them from directly referring to each other.  For example, refer back to our toolbar and form design earlier in the singleton discussion.  The buttons in the toolbar must provoke behaviors from the form (navigating in the cursor).  The forms must provoke behavior from the toolbar (enabling and disabling the buttons).  If the toolbar and form communicated directly with each other they would each need to be intimately aware of each other.  Each time the active form changed the toolbar would need to be notified.

Instead, in our design, we used the AppMgr as a mediator between the active form and the toolbar as in the figure below.

Strategy

Gamma and Helms et al describe a strategy pattern as;  “Strategy lets the algorithm vary independently from the clients that use it.”  In our examples the stream handler is an example of a strategy pattern as well as the decorator.  The XML handler class that is used varies the way the streams are processed.  This is done independently to the classes that use the stream processors.  Both the data access and the business logic classes use the stream processors and the processors can vary the way the streams are processed independently from the client (data access or business logic) that is using it.

Flyweight

Using object sharing to reduce the number of objects required serving a function.  The flyweight pattern allows the use of objects at a position where it might otherwise be a severe overhead due to the shear number of objects that might be required.

In our examples the Data Access objects are of the flyweight pattern.  Flyweight objects store only intrinsic state.  The key concept here is the difference between intrinsic and extrinsic context and state.  The following figure describes our data access objects.

Application Architectural Design

Introduction

The architecture of an application is the high level “block-diagram” of how the application is structured.  In common practice this design is often a result of “How we always did it” mentality.  The architecture of an application will influence all other decisions of design in that project.

There is no “correct” architectural design for applications.  Each design has its merits and its drawbacks.  There is, however, correct and incorrect implementations of any particular design.  What makes an implementation correct or incorrect is how closely it follows the “rules” of the design.

I have often heard the question, “What is the correct multi-tier design?”  There is no single answer to that question.  There are many good designs.  There are also many applications that did not follow the architecture design with which they started; these are examples of poor implementations.

In the following sections we will examine a couple of different architectures for application development.

Single Layer

Applications can be divided into “layers” of responsibility.  In the simplest design there is a single layer.  This one layer handles all activities of the application.  The figure below shows this design.

In this single layer design the single layer of the application handles all the activities of the application.  Visual FoxPro can easily be used to create these designs.

Advantages

All designs have both advantages and disadvantages.  The major benefit of the single layer design is the sheer simplicity of the design.  All functionality is contained in a single layer.

Visual FoxPro, because of its ease of “instance programming”, can lull a developer into the single layer design.  Writing code in the form designer often results in a single layer structure.

Disadvantages

Single layer architectures do not adapt to changes very easily.  Often a minor change in technology or requirements will result in a major rewrite of large portions of the application.

Multi-Layer

The next level of application architecture is to move from the single layer to multiple layers.  The major goal of moving to a multiple layered design is to achieve a componentization of the application layers.  The various layers of these multiple layered designs have very specific responsibilities.  These designs call for a separation of these responsibilities clearly into the layers in s

a fashion that the different layers do not over lap each other in activities.

Componentization

The word componentization means to enclose functionality into discrete components that can be interchanged to expand or enhance the application.  For example, a given application needs to store data.  Initially the application is distributed to a single department of a company.  Later the requirements change such that the data in this application must be shared with other applications in different departments, even departments that are located in different cities.

Ideally we should be able to simply open the data for sharing and be done with it.  However, in this situation there is a requirement for data security.  Our initial data storage system did not include a high level of data security because the data was local to the using department.  If we had achieved componentization of the data storage, then, in theory, we should be able to simply change the data storage system in use to one that provides the required security levels and make minor adaptations to the existing application.

Two Layers

The first multiple layered design we will examine is the two layered design, often called client-server design.  In the two-layered design we separate the presentation of the information from the storage of the data.  The figure below demonstrates this design.

In the figure you can see the two layers, presentation and data storage.  The presentation layer is responsible for displaying the data to the user and accepting input from the user.  The data storage layer is responsible for storing and retrieving the data to and from the storage media.

Notice in this design that the requests go in only one direction, from presentation to data storage, although the data moves in both directions.  The single direction of requests in a integral part of this design.

[ 1 ] [ 2 ] [ 3 ] [ 4 ] [ 5 ] [ 6 ]