design patterns

38
OBJECT ORIENTED DESIGN with UML and with UML and with UML and with UML and Java ava ava ava Part Part Part Part 4 Design Patterns Design Patterns Design Patterns Design Patterns LECTURE NOTES © EUGENE AGEENKO 2005

Upload: ritvikjain

Post on 21-Nov-2014

215 views

Category:

Documents


2 download

TRANSCRIPT

Page 1: Design Patterns

OBJECT ORIENTED DESIGN with UML and with UML and with UML and with UML and JJJJavaavaavaava

PartPartPartPart 4444 Design PatternsDesign PatternsDesign PatternsDesign Patterns

� LECTURE NOTES �

© EUGENE AGEENKO

2005

Page 2: Design Patterns
Page 3: Design Patterns

149

CONTENTS

CHAPTER E. DESIGN PATTERNS............................................................................................................ 151

E.1 INTRODUCTION....................................................................................................................................... 151 E.2 HIERARCHY OF DESIGN PATTERNS.......................................................................................................... 154

E.2.a Basic Concepts in Patterns ............................................................................................................... 154 E.2.b Patterns classification in Canonical form......................................................................................... 156 E.2.c Categorizing of Patterns by Intent .................................................................................................... 159

E.3 BASIC (FUNDAMENTAL ) PATTERNS........................................................................................................ 160 E.3.a The Constant Data Manager............................................................................................................. 161 E.3.b Delegation......................................................................................................................................... 163 E.3.c Interface ............................................................................................................................................ 166 E.3.d Abstract Superclass ........................................................................................................................... 168 E.3.e Interface and Abstract superclass together....................................................................................... 171 E.3.f Immutable.......................................................................................................................................... 172

E.4 CREATIONAL, BEHAVIORAL AND STRUCTURAL PATTERNS (REFERENCE) ............................................... 175 E.5 MODEL V IEW CONTROLLER ................................................................................................................... 175 E.6 PATTERNS IN JAVA API .......................................................................................................................... 178 E.7 PATTERNS BY INTENT ............................................................................................................................. 178

E.7.a Interfaces........................................................................................................................................... 179 E.7.b Responsibility .................................................................................................................................... 179 E.7.c Construction...................................................................................................................................... 180 E.7.d Operations......................................................................................................................................... 181 E.7.e Extensions ......................................................................................................................................... 183

E.8 RESOURCES............................................................................................................................................ 184

Page 4: Design Patterns
Page 5: Design Patterns

151

CHAPTER E. DESIGN PATTERNS

E.1 INTRODUCTION

WHAT IS A DESIGN PATTERN?

⋅ A design pattern is a documented best practice or core of a solution that has been applied successfully in multiple environments to solve a problem that recurs in a specific set of situations.

⋅ Architect Christopher Alexander describes a pattern as “a recurring solution to a common problem in a given context and system of forces.” In his definition, the term context refers to the set of conditions/situations in which a given pattern is applicable and the term system of forces refers to the set of constraints that occur in the specific context.

History of the Patterns Movement

⋅ The inspiration for design patterns in software development is usually attributed to Christopher Alexander, a professor of architecture at U.C. Berkeley. In the late ‘70s, he published several books that introduced the concept of patterns and provided a catalog of patterns for architectural design.

⋅ Alexander's work sparked interest in the object-oriented (OO) community, and within the next decade, a number of pioneers had developed patterns for software design. Kent Beck and Ward Cunningham were among the first, discussing a set of Smalltalk design patterns in a presentation at the 1987 OOPSLA conference. James Coplien was another who actively promoted the tenets of patterns, writing a book about C++ idioms, or patterns for C++ development, in the early ’90s.

⋅ OOPSLA was an excellent venue for the growing patterns community, since it offered an environment for them to share their ideas. Another important forum for the evolution of the patterns movement was the Hillside Group, established by Kent Beck and Grady Booch.

⋅ Probably the best-known contribution to the popularity of design patterns was the 1995 book Design Patterns: Elements of Reusable Object-Oriented Software. The authors—Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides—are also commonly known as the “Gang of Four” or GoF. The book introduced a comprehensive pattern language, and gave C++ examples for the patterns discussed. Another important work that gave momentum to patterns was the book Pattern-Oriented Software Architecture, A System of Patterns, by Buschmann, Meunier, Rohnert, Sommerlad and Stal.

⋅ Since the publication of these two books, design patterns have enjoyed substantial interest in the software community. Java (“Java technology”) grew up at the same time as patterns were gaining widespread popularity, so it was inevitable that Java developers would take an interest in applying design patterns in their projects. The growing popularity of design patterns in Java has been manifested in presentations at conferences like JavaOne, as well as patterns columns in the Java trade journals.

More about Design Patterns

⋅ A design pattern is an effective means to convey/communicate what has been learned about high-quality designs. The result is:

� A shared language for communicating the experience gained in dealing with these recurring problems and their solutions.

� A common vocabulary of system design elements for problem solving discussions. A means of reusing and building upon the acquired insight resulting in an improvement in the software quality in terms of its maintainability and reusability.

Page 6: Design Patterns

152

⋅ A design pattern is not an invention. A design pattern is rather a documented expression of the best way of solving a problem that is observed or discovered during the study or construction of numerous software systems.

⋅ One of the common misconceptions about design patterns is that they are applied only in an object-oriented environment. Even though design pat- terns discussions typically refer to the object-oriented development, they are applicable in other areas as well. With only minor changes, a design pattern description can be adjusted to refer to software design patterns in general. From the preceding section, Origin and History, it can be seen that patterns have existed from the early days of architecture, long before the object-oriented design and programming era.

⋅ Design patterns are not theoretical constructs. A design pattern can be seen as an encapsulation of a reusable solution that has been applied successfully to solve a common design problem.

⋅ Design patterns do not provide solutions to every problem found in real-world software design and development. Design patterns are about providing elegant, reusable solutions to commonly encountered software development problems in a particular context. This means that a pattern that is meant to provide the best solution to a problem in a particular context may not produce an effective solution to the same problem in a different context. Sometimes, the solution proposed by the design pattern may not even be applicable in a different context.

Design patterns and software frameworks

⋅ Software frameworks can be confused with design patterns. They are closely related. Table 1 lists the similarities and differences between the two.

Table 1. Similarities and differences between frameworks and patterns.

Design Patterns Frameworks

Design patterns are recurring solutions to problems that arise during the life of a software application in a particular context.

A framework is a group of components that cooperate with each other to provide a reusable architecture for applications with a given domain.

The primary goal is to:

• Help improve the quality of the software in terms of the software being reusable, maintainable, extensible, etc.

• Reduce the development time

The primary goal is to:

• Help improve the quality of the software in terms of the software being reusable, maintainable, extensible, etc.

• Reduce development time

Patterns are logical in nature. Frameworks are more physical in nature, as they exist in the form of some software.

Pattern descriptions are usually independent of programming language or implementation details.

Because frameworks exist in the form of some software, they are implementation-specific.

Patterns are more generic in nature and can be used in almost any kind of application.

Frameworks provide domain-specific functionality.

A design pattern does not exist in the form of a software component on its own. It needs to be implemented explicitly each time it is used.

Frameworks are not complete applications on their own. Complete applications can be built by either inheriting the components const directly.

Page 7: Design Patterns

153

Patterns provide a way to do “good” design and are used to help design frameworks.

Design patterns may be used in the design and implementation of a framework. In other words, frameworks typically embody several design patterns.

Software abstraction and reuse

⋅ Design patterns represent an important evolutionary step in software abstraction and reuse. These two concepts are central to the idea of programming—some would say they are the two most important ones.

⋅ Abstraction represents a way for developers to solve complex problems by breaking them up into progressively simpler ones. The solutions to simpler problems, when “tagged” with a label or name, can then be used as building blocks to solve the more complicated projects that we as developers encounter each day.

⋅ Reuse is equally vital to software development. In a sense, the history of software development is marked by a constant search to find progressively more sophisticated ways to reuse code. Why all the interest? What's the motivation? Actually, reuse is a perfectly understandable goal given the nature of software development. After all, given a complicated software project complete with a tight deadline schedule, which would you rather do? (Select the best answer.)

⋅ Write all the code from scratch, subjecting yourself and those around you to a slow and painful process of testing and validating everything that you write.

⋅ Use proven and tested code as the foundation for your work.

⋅ Don't get me wrong—coding is a blast. It's the testing, debugging, documentation, and post-release support that we developers don't generally like all that much. Over the years, we've come up with quite a few ways to reuse code and development concepts.

⋅ The earliest kind of reuse was snippet reuse (a.k.a. CaP – Cut and Paste). The less said about this as a method for effective software reuse, the better. Likewise, this approach does not offer any real qualitative benefits in terms of code abstraction.

⋅ Algorithmic reuse provided a more general way to manage reuse. You can reuse an algorithm, like searching and sorting, to abstract an approach (usually mathematical) to solving a particular kind of computing problem.

⋅ Functional reuse, and its counterpart, data structure reuse, allow you to reuse a coding abstraction more directly. For example, any developer who wants to model something like an address could define a structure with all the necessary fields, and then reuse the structure in any project which required an address. Likewise, an operation like computeTax could be defined as a function (or procedure or subroutine or method, depending on the programming language), and subsequently copied as a whole to new projects.

⋅ Two extensions of these reuse concepts are the function library and the API. They represent ways to package functionality and make functionality available to future applications without actually having to copy code.

⋅ The development of object-oriented languages represents a tremendous evolutionary leap forward in terms of abstraction and reuse. With this technology, an entire generation of more sophisticated ways to get more mileage out of code was born.

⋅ The concept of the class as blueprint for objects provided a major advancement by combining two earlier mechanisms: functional and data abstraction. By packaging an entity’s structure (data) with functionality that applies to the entity (behavior), you gain a way to effectively reuse a software element.

Page 8: Design Patterns

154

⋅ Beyond the core concept of the class, object-oriented languages give us a variety of other ways to leverage existing code. The concepts of subclasses and interfaces, for instance, opened new possibilities for reuse in software development. Finally, groups of classes can be associated with each other and effectively be treated as a logical software component, providing a very powerful model for reuse at the system level.

⋅ In the Table 2, the Reusability heading indicates the repeatability of the approach. Abstraction is an indication of what has been abstracted. Genericity shows how easy it is to apply this method without rewriting or modifying code. Note that the reusability of these approaches heavily depends on how effectively the techniques are applied. Clearly, any capability can be used or misused.

Table 2. Comparing approaches for reuse and abstraction

Type of reuse Reusability Abstraction Genericity

Snippet Very poor Nothing Very poor

Data structures Good Data type Moderate – good

Functional Good Method Moderate – good

Template Good Operation to type Good

Algorithmic Good Formula Good

Class Good Data + method Good

Interface

Polymorphism

Abstract class

Interface

Code library Good Functions Good – very good

API Good Utility classes Good – very good

Component Good Group of classes Good – very good

Design pattern Excellent Problem solution Very good

E.2 HIERARCHY OF DESIGN PATTERNS

E.2.a Basic Concepts in Patterns

⋅ Central to the idea of patterns is the concept of standardizing the information about a common problem and its solution. One of the most useful results of Alexander's work was the development of a template for representing patterns — what is now called a form or format. The Alexandrian Form uses five topic areas to formalize the discussion of a pattern and its solution.

⋅ Fundamentally, it’s important that a pattern provide a descriptive name for the pattern and the answer to the question “What will this pattern do for you?” In addition, it should include a discussion of the problem, an explanation of how the pattern solves the problem, and an indication of the benefits, drawbacks and tradeoffs associated with the pattern’s use.

⋅ Naturally, when patterns were adopted by the OO community, variations on the Alexandrian form were developed to meet the needs of software development. Most of the forms in use today are derived from one of two forms—the Canonical or “Gang of Four” forms. The following template is usually used for describing the patterns:

Page 9: Design Patterns

155

⋅ Name – a descriptive name for the pattern.

⋅ Also Known As – alternate names, if any.

⋅ Pattern Properties – the pattern's classification. We define a pattern in terms of two major topics.

⋅ Type:

� Creational – patterns for object creation

� Behavioral – patterns that coordinate functional interaction between objects

� Structural – patterns that manage static, structural relationships between objects

� System – patterns used to manage system-level interaction

⋅ Level:

� Single Class – the pattern applies to a single class

� Component – the pattern involves a group of classes

� Architectural – the pattern is used to coordinate the actions of systems and subsystems

⋅ Purpose (or Synopsis) – a short explanation of what the pattern involves.

⋅ Introduction (or Context) – a brief description of a problem you might be facing where this pattern may be useful, using an example to illustrate.

⋅ Applicability (or Forces) – when and why you might want to use this design pattern. This section summarizes the considerations that lead to the general solution presented in the Solution section. It may also present reasons to not use the solution. The reasons to use or not use the solution are presented as a bulleted list:

☺ Reasons to use the solution are bulleted with a happy face

� Reasons to not use the solution are bulleted with a sad face

⋅ Description (or Solution) – a detailed discussion of the pattern, what it does and how it behaves. This is the core of the pattern. It describes a general-purpose solution to the problem that the pattern addresses.

⋅ Benefits and Drawbacks (or Consequences) – the consequences of using the pattern and tradeoffs associated with use of the pattern. The Consequences section explains the implications––good and bad––of using the solution. Most consequences are organized into bullet points as follows:

☺ Good consequences are bulleted with a happy face.

� Neutral consequences are bulleted with a dot.

� Bad consequences are bulleted with a sad face.

⋅ Implementation – a discussion of what must be done to implement the pattern. The Implementation section describes important considerations when using the solution.

Pattern Variants – possible implementation alternatives and variations on the pattern (can be merged with Implementation)

⋅ Related Patterns – other patterns that are either associated with or closely related to the pattern.

⋅ Example – a (Java) code example.

Page 10: Design Patterns

156

E.2.b Patterns classification in Canonical form

Table 3. Categories of design patterns in Canonical form

Creational Behavioral Structural System Concurrency (new)

Singleton

Abstract Factory

Builder

Factory Method

Prototype

Chain of Responsibility

Mediator

Observer

Memento

Command

Interpteror

State

Strategy

Template Method

Iterator

Visitor

Flyweight

Proxy

Adapter

Bridge

Composite

Facade

Decorator

MVC

Session

Worker Thread

Callback

Successive Update

Router

Transaction

Single Threaded Execution

Lock Object

Balking

Read/Write Lock

Produce-Consumer

Two-phase termination

Double Buffering

Asynchronous Processing

Future

Creational Patterns

⋅ These patterns support one of the most common tasks in object-oriented programming—the creation of objects in a system. Most OO systems of any complexity require many objects to be instantiated over time, and these patterns support the creation process by helping to provide the following capabilities:

⋅ Generic instantiation – This allows objects to be created in a system without having to identify a specific class type in code.

⋅ Simplicity – Some of the patterns make object creation easier, so callers will not have to write large, complex code to instantiate an object.

⋅ Creation constraints – Some patterns enforce constraints on the type or number of objects that can be created within a system.

⋅ The following are the most common used creational patterns:

� Abstract Factory – To provide a contract for creating families of related or dependent objects without having to specify their concrete classes.

� Builder – To simplify complex object creation by defining a class whose purpose is to build instances of another class. The Builder produces one main product, such that there might be more than one class in the product, but there is always one main class.

� Factory Method – To define a standard method to create an object, apart from a constructor, but the decision of what kind of an object to create is left to subclasses.

� Prototype – To make dynamic creation easier by defining classes whose objects can create duplicates of themselves.

� Singleton – To have only one instance of this class in the system, while allowing other classes to get access to this instance.

⋅ Of these patterns, the Abstract Factory and Factory Method are explicitly based on the concept of defining flexible object creation; they assume that the classes or interfaces to be created will be extended in an implementing system. As a result, these two patterns are frequently combined with other creational patterns.

Page 11: Design Patterns

157

Behavioral patterns

⋅ Behavioral patterns are concerned with the flow of control through a system. Some ways of organizing control within a system can yield great benefits in both efficiency and maintainability of that system. Behavioral patterns distill the essence of proven practices into readily understood, well known, and easy-to-apply heuristics.

⋅ Most common behavioral patterns are as follows:

� Chain of Responsibility – To establish a chain within a system, so that a message can either be handled at the level where it is first received, or be directed to an object that can handle it.

� Command – To wrap a command in an object so that it can be stored, passed into methods, and returned like any other object.

� Interpreter – To define an interpreter for a language.

� Iterator – To provide a consistent way to sequentially access items in a collection that is independent of and separate from the underlying collection.

� Mediator – To simplify communication among objects in a system by introducing a single object that manages message distribution among the others.

� Memento – To preserve a “snapshot” of an object’s state, so that the object can return to its original state without having to reveal its content to the rest of the world.

� Observer – To provide a way for a component to flexibly broadcast messages to interested receivers.

� State – To easily change an object’s behavior at runtime.

� Strategy – To define a group of classes that represent a set of possible behaviors. These behaviors can then be flexibly plugged into an application, changing the functionality on the fly.

� Visitor – To provide a maintainable, easy way to perform actions for a family of classes. Visitor centralizes the behaviors and allows them to be modified or extended without changing the classes they operate on.

� Template Method – To provide a method that allows subclasses to override parts of the method without rewriting it.

Structural patterns

⋅ Structural patterns describe effective ways both to partition and to combine the elements of an application. The ways structural patterns affect applications varies widely: for instance, the Adapter pattern can let two incompatible systems communicate, while Facade lets you present a simplified interface to a user without removing all the options available in the system.

⋅ Most common structural patterns are:

� Adapter – To act as an intermediary between two classes, converting the interface of one class so that it can be used with the other.

� Bridge – To divide a complex component into two separate but related inheritance hierarchies: the functional abstraction and the internal implementation. This makes it easier to change either aspect of the component.

� Composite – To develop a flexible way to create hierarchical tree structures of arbitrary complexity, while enabling every element in the structure to operate with a uniform interface.

Page 12: Design Patterns

158

� Decorator – To provide a way to flexibly add or remove component functionality without changing its external appearance or function.

� Facade – To provide a simplified interface to a group of subsystems or a complex subsystem.

� Flyweight – To reduce the number of very low-level, detailed objects within a system by sharing objects.

� Proxy – To provide a representative of another object, for reasons such as access, speed, or security.

System patterns

⋅ System patterns are the most diverse of the four pattern types. They embrace your application at its most abstract, architectural level. System patterns can apply to major processes within an application, or even between applications. System patterns include the following:

� Model-View-Controller (MVC) – To divide a component or subsystem into three logical parts—model, view, and controller—making it easier to modify or customize each part.

� Session – To provide a way for servers in distributed systems to distinguish among clients, allowing applications to associate state with the client-server communication.

� Worker Thread – To improve throughput and minimize average latency.

� Callback – To allow a client to register with a server for extended operations. This enables the server to notify the client when the operation has been completed.

� Successive Update – To provide a way for clients to receive updates from a server on an ongoing basis. The updates generally reflect a change in server data, a new or updated resource, or a change in the state of the business model.

� Router – To decouple multiple sources of information from the targets of that information.

� Transaction – To group a collection of methods so that they either all succeed or they all fail collectively.

Concurrency patterns

⋅ These patterns involve coordinating concurrent operations. These patterns primarily address two types of problems:

� Shared resources. When concurrent operations access the same data or another type of shared resource, operations may interfere with each other if they access the resource at the same time. To ensure that operations on shared resources execute correctly, the operations must be sufficiently constrained to access their shared resource one at a time. However, if the operations are overly constrained, then they may deadlock and not be able to finish executing.

� Deadlock is a situation where one operation waits for another operation to do something before it proceeds. Because each operation is waiting for the other to do something, they wait forever and never do anything.

� Sequence of operations. If operations are constrained to access a shared resource one at a time, it may be necessary to ensure that they access the shared resource in a particular order. For example, an object cannot be removed from a data structure before it is added to the data structure.

⋅ The Concurrency patterns are as follows:

Page 13: Design Patterns

159

� Most shared-resource issues can be resolved with just the Single Threaded Execution pattern, which ensures that no more than one thread at a time can access a resource. Situations where the sequence of operations matters are less common. Such situations can be handled using the Scheduler pattern.

� The Guarded Suspension pattern provides guidance on what to do when a thread has exclusive access to a resource and discovers that it cannot complete the operation on that resource because something is not yet ready.

� When an operation may require exclusive access to multiple resources, the Lock Object pattern is a way to simplify coordination of access to the multiple resources.

� The Balking pattern is useful if an operation must be done either immediately or not at all.

� The Read/Write Lock pattern is an alternative to one-at-a-time access if some operations can share the same resource and some operations cannot share.

� The Producer-Consumer pattern is useful for coordinating objects that produce a resource with objects that consume the resource.

� The Two-Phase Termination pattern is used to shut down threads in an orderly way.

� The Double Buffering pattern is a specialized form of the Producer-Consumer pattern that makes it more likely resources will be produced before they are needed.

� The Asynchronous Processing pattern describes how to avoid waiting for the results of an operation when you don’t need to know the result immediately.

� The Future pattern describes how to keep classes that invoke an operation from having to know whether the operation is synchronous or asynchronous.

E.2.c Categorizing of Patterns by Intent

⋅ A pattern is a way of doing something, a way of pursuing intent. A design pattern is a way of pursuing an intent using object technology: classes and their methods, inheritance, and interfaces. Developers often start thinking about design after learning a programming language and writing code for a while. You might notice that someone else's code seems simpler and works better than yours does, and you might wonder how that person achieves this simplicity. Design patterns are a level up from code and typically show how to achieve a goal, using one to ten classes. Other people have figured out how to program effectively in object-oriented languages. If you want to become a powerful Java programmer, you should study design patterns, especially those in Design Patterns.

⋅ The most important aspect of any pattern is its intent, that is, the potential value of applying the pattern. The intent of a design pattern is usually easily expressed as the need to go beyond the ordinary facilities that are built into Java. For example, Java has plentiful support for defining the interfaces that a class implements. But if you want to adapt a class's interface to meet the needs of a client, you need to apply the Adapter pattern. The intent of the Adapter pattern goes beyond the interface facilities built into Java.

Table 4. Categorization of Patterns by Intent

INTENT PATTERNS

INTERFACES ADAPTER, FACADE, COMPOSITE, BRIDGE

RESPONSIBILITY SINGLETON, OBSERVER, MEDIATOR, PROXY, CHAIN OF RESPONSIBILITY, FLYWEIGHT

CONSTRUCTION BUILDER, FACTORY METHOD, ABSTRACT FACTORY, PROTOTYPE, MEMENTO

OPERATIONS TEMPLATE METHOD, STATE, STRATEGY, COMMAND, INTERPRETER

EXTENSIONS DECORATOR, ITERATOR, VISITOR

Page 14: Design Patterns

160

Table 5. Combined hierarchy of design patterns

Intent Creational Behavioral Structural

Responsibility Singleton Chain of Responsibility

Mediator

Observer

Flyweight

Proxy

Interface Adapter

Bridge

Composite

Facade

Construction Abstract Factory

Builder

Factory Method

Prototype

Memento

Operation Command

Interpteror

State

Strategy

Template Method

Extension Iterator

Visitor

Decorator

E.3 BASIC (FUNDAMENTAL) PATTERNS

Introduction

⋅ These patterns are some of the most common, basic and important design patterns one can find in the areas of object-oriented design and programming. Some of these fundamental design patterns, such as the Interface, Abstract Parent, Private Methods, etc., are used extensively during the discussion of the other patterns. The Java programming language has built-in support for some of the fundamental design patterns in the form of language features. The other fundamental patterns can very easily be implemented using the Java language constructs.

1. Delegation

� Inheritance is a common way to extend and reuse the functionality of a class. Delegation is a more general way for extending a class’s behavior that involves a class calling another class’s methods rather than inheriting them. Though less convenient, delegation is a more general-purpose way of extending classes that succeeds in many situations where inheritance does not work well.

2. Interface

� Can be used to design a set of service provider classes that offer the same service so that a client object can use different classes of service provider objects in a seamless manner without having to alter the client implementation.

3. Abstract Superclass

� Useful for designing a framework for the consistent implementation of the functionality common to a set of related classes

4. Private Methods

Page 15: Design Patterns

161

� Provide a way of designing a class behavior so that external objects are not permitted to access the behavior that is meant only for the internal use.

5. Accessor Methods

� Provide a way of accessing an object’s state using specific methods. This approach discourages different client objects from directly accessing the attributes of an object, resulting in a more maintainable class structure.

6. Constant Data Manager

� Useful for designing an easy to maintain, centralized repository for the constant data in an application.

7. Immutable Object

� Used to ensure that the state of an object cannot be changed. May be used to ensure that the concurrent access to a data object by several client objects does not result in race conditions.

References and Examples - Read DP_Basic.pdf

⋅ The patterns in this chapter are the most fundamental and important design patterns to know. You will find these patterns used extensively in other design patterns. The Delegation; Interface; Abstract Superclass; and Interface and Abstract Class patterns demonstrate how to organize relationships between classes. Most patterns use at least one of these patterns.

⋅ The Immutable Object pattern describes a way to avoid bugs and delays when multiple objects access the same object. Although this pattern is not explicitly part of the majority of other patterns, it can be used advantageously with most patterns.

⋅ The Constant Data Manager pattern is useful for designing an efficient storage mechanism for the constant data used by different objects in an application.

E.3.a The Constant Data Manager

Synopsis

⋅ The Constant Data Manager pattern is useful for designing an efficient storage mechanism for the constant data used by different objects in an application.

Context

⋅ Objects in an application usually make use of different types of data in offering the functionality they are designed for. Such data can either be variable data or constant data. In general, application objects access different types of constant data items such as data file names, button labels, maximum and minimum range values, error codes and error messages, etc.

Solution

⋅ Instead of allowing the constant data to be present in different objects, the Constant Data Manager pattern recommends all such data, which is considered as constant in an application, be kept in a separate object and accessed by other objects in the application. This type of separation provides an easy to maintain, centralized repository for the constant data in an application.

Example

⋅ Let us consider a Customer Data Management application that makes use of three types of objects — Account, Address and CreditCard — to represent different parts of the

Page 16: Design Patterns

162

customer data. Each of these objects makes use of different items of constant data as part of offering the services it is designed for.

⋅ Instead of allowing the distribution of the constant data across different classes, it can be encapsulated in a separate ConstantDataManager (Figure 1) object and is accessed by each of the Account, Address and CreditCard objects. The interaction among these classes can be depicted as in Figure 2.

public class ConstantDataManager {

public static final String ACCOUNT_DATA_FILE = "ACCOUNT.TXT";

public static final int VALID_MIN_LNAME_LEN = 2;

public static final String ADDRESS_DATA_FILE = "ADDRESS.TXT";

public static final int VALID_ST_LEN = 2;

public static final String VALID_ZIP_CHARS = "0123456789";

public static final String DEFAULT_COUNTRY = "USA";

public static final String CC_DATA_FILE = "CC.TXT";

public static final String VALID_CC_CHARS = "0123456789";

public static final String MASTER = "MASTER";

public static final String VISA = "VISA";

public static final String DISCOVER = "DISCOVER";

}

Figure 1. The ConstantDataManager class listing.

Address

save()

<<uses>>

ConstantDataManager

final ACCOUNT_DATA_FILE:String ="ACCOUNT.TXT" final VALID_MIN_LNAME_LEN:int =2

final ADDRESS_DATA_FILE:String ="ADDRESS.TXT" final VALID_ST_LEN:int =2 final VALID_ZIP_CHARS:String ="0123456789" final DEFAULT_COUNTRY:String ="USA"

final CC_DATA_FILE:String ="CC.TXT" final VALID_CC_CHARS:String ="0123456789" final MASTER:String ="MASTER" final VISA:String ="VISA" final DISCOVER:String ="DISCOVER"

<<uses>>

Account

save()

save()

<<uses>>

CreditCard

save()

Figure 2. The Constant Data Manager class illustration.

Consequences

☺ Whenever any of the constant data items needs to be modified, only the Constant Data Manager needs to be altered without affecting other application objects.

� On the other side, it is easy to lose track of constants that do not get used anymore when code gets thrown out over the years but constants remain in the class.

Page 17: Design Patterns

163

E.3.b Delegation

Synopsis

⋅ In some situations, using inheritance to extend a class leads to a bad design. Though less convenient, delegation is a more general-purpose way of extending classes. Delegation succeeds in many situations where inheritance does not work well.

Context

⋅ Inheritance is a common way to extend and reuse the functionality of a class. Delegation is a more general way for extending a class’s behavior that involves a class calling another class’s methods rather than inheriting them. Inheritance is inappropriate for many situations in which delegation is appropriate.

⋅ For example, inheritance is useful for capturing “is-a-kind-of” relationships because of their static nature. However, “is-a-role-played-by” relationships are awkward to model by inheritance. Instances of a class can play multiple roles. Consider the example of an airline reservation system that includes such roles as passenger, ticket-selling agent, and flight crew. It’s possible to represent these role relationships as a class called Person that has subclasses corresponding to these roles, as shown in Figure 3.

Figure 3. Modeling roles with inheritance.

Figure 4. Modeling multiple roles with Inheritance.

⋅ The problem with the model in Figure 3 is that the same person can fill more than one of these roles. A person who is normally part of a flight crew can also be a passenger. Some airlines occasionally float flight crew members to the ticket counter, which means that the same person can fill any combination of these roles. To model this situation, you would need seven subclasses for Person, as shown in Figure 4. The number of subclasses needed

Page 18: Design Patterns

164

increases exponentially with the number of roles. To model all the combinations of six roles would require 63 subclasses.

⋅ A more serious problem is that the same person may play different combinations of roles at different times. Inheritance relationships are static and do not change over time. To model different combinations of roles over time using inheritance relationships, it is necessary to use different objects at different times to represent the same person in order to capture changes in role. Modeling dynamically changing roles with inheritance gets complicated.

⋅ On the other hand, it is possible to represent persons in different roles using delegation without having any of these problems. Figure 5 shows how the model could be reorganized using delegation.

Figure 5. Modeling roles with delegation.

⋅ Using the organization shown in Figure 5, a Person object delegates the responsibility of filling a particular role to an object that is specific to that role. You need only as many objects as there are roles to fill. Different combinations do not require additional objects. Because delegation objects can be dynamic, role objects can be added or removed as a person fills different roles.

⋅ In the case of the airline reservation software, a predetermined set of role objects may become associated with different Person objects over time. For example, when a flight is scheduled, it will be determined that a certain number of flight crewmembers must be on board. When a flight is staffed, specific persons will be associated with crewmember roles. As schedules change, a person may be shifted from one crewmember role to another.

Forces

☺ Inheritance is a static relationship; it does not change over time. If it is found that an object needs to be a different subclass of a class at different times, it should not have been made a subclass of that class in the first place. If an object is created as an instance of a class, it will always be an instance of that class. However, an object can delegate behavior to different objects at different times.

☺ If it is found that a class attempts to hide a method or variable inherited from a superclass from other classes that class should not inherit from the superclass. There is no effective way to hide methods or variables inherited from a superclass. However, it is possible for an object to use another object’s methods and variables while ensuring that it is the only object with access to the other object. This accomplishes the same thing as inheritance but uses dynamic relationships that can change over time.

☺ A class related to a program’s problem domain should not be a subclass of a utility class. There are two reasons for this:

1) If a class is declared a subclass of a class such as ArrayList or HashMap, there is risk that these classes not under your control will change in an incompatible way. Though the risk is low, usually there is no corresponding benefit to offset it.

Page 19: Design Patterns

165

2) When a problem-domain-specific class as a subclass of a utility class is written, usually the intention is to use the functionality of the utility class for implementing problem-domain-specific functionality. The problem with using inheritance this way is that it weakens the encapsulation of the problem domain class’s implementation.

⋅ Client classes that use the problem-domain-specific class may be written in a way that assumes the problem-domain-specific class to be a subclass of the utility class. If a change to the implementation of the problem domain class gives it a different superclass, client classes that rely on the problem-domain class having its original superclass will break.

⋅ An even more serious problem is that client classes can call the public methods of the utility superclass, thereby defeating its encapsulation.

� Delegation can be less convenient than inheritance, because it requires more code to implement.

� Delegation imposes less structure on classes than inheritance. In designs in which constraining the structure of classes is important, the structure and inflexibility of inheritance may be a virtue. This is often true in frameworks. See the discussion of the Template Method pattern for more details of this issue.

⋅ Some inappropriate uses of inheritance are sufficiently common to be classified as AntiPatterns. In particular, subclassing utility classes and using inheritance to model roles are common design flaws.

☺ Most reuse and extension of a class is not appropriately done through inheritance.

☺ The behavior that a class inherits from its superclass cannot be easily changed over time. Inheritance is not useful when the behavior on which a class should build is not determined until runtime.

Solution

⋅ Use delegation to reuse and extend the behavior of a class. You do this by writing a new class (the delegator) that incorporates the functionality of the original class by using an instance of the original class (the delegatee) and calling its methods.

⋅ Figure 6 shows that a class in a Delegator role uses a class in the Delegatee role.

Figure 6. Delegation.

⋅ Delegation is more general purpose than inheritance. Any extension to a class that can be accomplished by inheritance can also be accomplished by delegation.

Implementation

⋅ The implementation of delegation is very straightforward, for it simply involves the acquisition of a reference to an instance of the class to which you want to delegate and call its methods.

⋅ The best way to ensure that a delegation is easy to maintain is to make its structure and purpose explicit. One way to do this is to make the delegation through an interface using the Interface pattern.

Consequences

⋅ Delegation can be used without the problems that accompany inheritance. Delegation allows behavior to be easily composed at runtime.

Page 20: Design Patterns

166

⋅ The main disadvantage is that delegation is less structured than inheritance. Relationships between classes built by using delegation are less obvious than those built by using inheritance. The following are some strategies for improving the clarity of delegation-based relationships:

� Use consistent naming schemes to refer to objects in a particular role. For example, if multiple classes delegate the creation of widget objects, the role of the delegatee object becomes more obvious if all of the classes delegating that operation refer to delegatee objects through a variable called widgetFactory

� You can clarify the purpose of a delegation by writing comments

� Follow the Law of Demeter pattern (described in Patterns in Java, Volume 2), which says that if without a delegation a class would have only an indirect association with another class, the delegation should be indirect. Do not directly delegate behavior to an indirectly associated class that provides the behavior; instead, delegate it to a directly associated class and have that class delegate the behavior to the class that provides the behavior. Doing so simplifies the overall design by minimizing the number of associations between objects. In extreme cases, however, these indirect delegations can make an intermediate class less coherent by adding methods unrelated to the class’s purpose. In such cases, refactor the unrelated words into a separate class by using the Pure Fabrication pattern (also described in Patterns in Java, Volume 2).

� Use well-known design and coding patterns. A person reading code that uses delegation will be more likely to understand the role that the objects play if the roles are part of a well-known pattern or a pattern that recurs frequently in your program.

⋅ It is not only possible but advantageous to use all three strategies at the same time.

Java API Usage

⋅ The Java API is full of examples of delegation. It is the basis for Java’s delegation event model in which event source objects send events to event listener objects. Event source objects do not generally decide what to do with an event; instead, they delegate the responsibility of processing the event to listener objects.

E.3.c Interface

Synopsis

⋅ Instances of a class provide data and services to instances of other classes. You want to keep client classes independent of specific data-and-service-providing classes so you can substitute another data-and-service-providing class with minimal impact on client classes. You accomplish this by having other classes access the data and services through an interface.

Context

⋅ Suppose you are writing an application to manage the purchase of goods for a business. Among the entities your program needs to know about are vendors, freight companies, receiving locations, and billing locations. One common aspect of these entities is that they all have street addresses. These street addresses appear in different parts of the user interface. You want to have a class for displaying and editing street addresses so that you can reuse it wherever there is a street address in the user interface. We call this class AddressPanel.

⋅ You want AddressPanel objects to get and set address information in a separate data object. This raises the question of what the AddressPanel class assumes about the class of data objects with which it will work. Clearly, you will use different classes to represent vendors, freight companies, and the like.

Page 21: Design Patterns

167

⋅ You can solve the problem by creating an address interface. Instances of the AddressPanel class would then simply require the data objects that they work with to implement the address interface. They would call the accessor methods of the interface to get and set the object’s address information.

⋅ By using the indirection that the interface provides, clients of the AddressPanel interface are able to call the methods of a data object without having to be aware of what class it belongs to. Figure 7 is a class diagram showing these relationships.

Forces

☺ An object relies on another object for data or services. If the object must assume that the other object upon which it relies belongs to a particular class, the reusability of the object’s class would be compromised.

☺ You want to vary the kind of object used by other objects for a particular purpose without making the object dependent on any class other than its own.

� A class’s constructors cannot be accessed through an interface, because Java’s interfaces cannot have constructors.

Figure 7. Indirection through address Interface.

Solution

⋅ To avoid classes having to depend on other classes because of a uses/used-by relationship, make the usage indirect through an interface. Figure 8 shows this relationship.

⋅ The following are the roles that these classes and interfaces play:

� Client. The Client class uses classes that implement the IndirectionIF interface.

� IndirectionIF. The IndirectionIF interface provides indirection that keeps the Client class independent of the class that is playing the Service role. Interfaces in this role are generally public.

� Service. Classes in this role provide a service to classes in the Client role. Classes in this role are ideally private to their package. Making Service classes private forces classes

Page 22: Design Patterns

168

outside of their package to go through the interface. However, it is common to have implementations of an interface that are in different packages.

Figure 8. Interface pattern.

Implementation

⋅ Implementation of the Interface pattern is straightforward. Define an interface to provide a service, write client classes to access the service through the interface, and write service-providing classes that implement the interface.

⋅ Java interfaces cannot have constructors. For this reason, interfaces are not helpful in keeping a class responsible for creating objects independent of the class of objects that it creates. The Java API includes a class called java.lang.reflect.Constructor that can be used to construct objects without knowing what class they will be an instance of.

Consequences

� Applying the Interface pattern keeps a class that needs a service from another class from being coupled to any specific class.

� Like any other indirection, the Interface pattern can make a program more difficult to understand.

Java API Usage

⋅ The Java API defines the interface java.io.FilenameFilter. This interface declares a method called accept. The accept method takes an argument that is a filename. The method is supposed to return true or false to indicate whether the named file should be included in a collection. The Java API also provides the java.awt.FileDialog class that can use a FilenameFilter object to filter the files that it displays.

E.3.d Abstract Superclass

Synopsis

⋅ Ensure consistent behavior of conceptually related classes by giving them a common abstract superclass.

Context

⋅ You want to write classes to provide sequential and read-only access to some data structures. You decide that these classes will implement the interface java.util.Iterator.

Page 23: Design Patterns

169

⋅ The Iterator interface includes a method called remove. The documented purpose of the remove method is to remove objects from the source over which an Iterator object iterates. However, the description of the remove method also says that it is an optional method; an implementation of the method may simply throw an UnsupportedOperationException.

⋅ Because your intention is to provide read-only access to data structures, you want all of your classes to implement the remove method by throwing an UnsupportedOperationException. To ensure that these classes implement the remove method in the same way, you create a common abstract class for all of your Iterator classes to inherit from. The common superclass implements the remove method by having it always throw an UnsupportedOperationException. This organization is shown in Figure 9.

Forces

☺ You want to ensure that logic common to related classes is implemented consistently for each class.

☺ You want to avoid the runtime and maintenance overhead of redundant code.

☺ You want to make it easy to write related classes.

� You want to organize common behavior, although in many situations, inheritance is not an appropriate way to accomplish this. The Delegation pattern describes this in detail

Figure 9. Iterators with abstract superclass.

Solution

⋅ Organize the common behavior of related classes into an abstract superclass.

⋅ To the extent possible, organize variant behavior into methods with common signatures.2 Declare the abstract superclass to have abstract methods with these common signatures. Figure 10 shows this organization.

Page 24: Design Patterns

170

⋅ The following are the roles that classes play in the Abstract Superclass pattern:

� Abstract_Superclass. A class in this role is an abstract superclass that encapsulates the common logic for related classes. The related classes extend this class so they can inherit methods from it. Methods whose signature and logic are common to the related classes are put into the superclass so their logic can be inherited by the related classes that extend the superclass. Methods with different logic but the same signature are declared in the abstract class as abstract methods, ensuring that each concrete subclass has a method with those signatures.

� Concrete_Class_1, Concrete_Class_2, and so on. A class in this role is a concrete class whose logic and purpose is related to other concrete classes. Methods common to these related classes are refactored into the abstract superclass.

⋅ Common logic that is not encapsulated in common methods is refactored into common methods.

Figure 10. Abstract Superclass pattern.

Implementation

⋅ If the common method signatures are public, they should, if possible, be organized into a Java interface that the abstract class implements.

Consequences

☺ Fewer test cases may be needed to completely test your classes, because there are fewer pieces of code to test.

� Using the Abstract Superclass pattern creates dependencies between the superclass and its subclasses. Changes to the superclass may have unintended effects on some subclasses, thus making the program harder to maintain.

Page 25: Design Patterns

171

Java API Usage

⋅ The class java.awt.AWTEvent is an abstract class for classes that encapsulate events related to the graphical user interface (GUI). It defines a small number of methods that are common to user-interface event classes.

E.3.e Interface and Abstract superclass together

Synopsis

⋅ You need to keep client classes independent of classes that implement a behavior and ensure consistency of behavior between the behavior-implementing classes. Don’t choose between using an interface and an abstract class; have the classes implement an interface and extend an abstract class.

Context

⋅ You are designing a framework. You want to hide the class or classes that implement some behavior by making the classes private to their package and having them implement a public interface. For the sake of consistency and convenience of implementation, you want the classes to extend a common abstract class. You are not sure how to decide between basing the classes on an interface and an abstract class.

Forces

☺ Using the Interface pattern, Java interfaces can be used to hide the specific class that implements a behavior from the clients of the class.

☺ Organizing classes that provide related behaviors with a common superclass helps to ensure consistency of implementation. Through reuse, it may also reduce the effort required for implementation.

� When people are presented with two different ways to improve the organization of classes, there is a common tendency to choose either one or the other.

Solution

⋅ If you are presented with the need to hide from its clients the class of an object that provides a service, then use the Interface pattern. Have the client objects access the service-providing object indirectly through an interface. The indirection allows the clients to access the service-providing object without having to know what kind of objects they are.

⋅ If you need to design a set of related classes that provide similar functionality, then organize the common portions of their implementation into an abstract superclass.

⋅ If you are presented with both of these needs in the same object design, then use both an interface and an abstract class as shown in Figure 11.

⋅ When using the combination of an interface and abstract class in this way, the interface is public; the abstract class is package private, if possible.

Consequences

☺ Using the Interface and Abstract Class pattern allows an object design to benefit from both an interface and an abstract class.

Page 26: Design Patterns

172

Figure 11. Interface and abstract class.

Java API Usage

⋅ The package javax.swing.table contains interfaces and classes to support tables in a user interface. For every table that appears in a user interface, a corresponding data model object contains the data values displayed in the table. To be used as the data model for a table, an object must be an instance of a class that implements the javax.swing.table.TableModel interface. The package also includes a class named AbstractTableModel. AbstractTableModel is an abstract class that contains some default logic useful in implementing the methods declared by the TableModel interface.

E.3.f Immutable

Synopsis

⋅ The Immutable pattern increases the robustness of objects that share references to the same object and reduces the overhead of concurrent access to an object. It achieves this by not allowing the shared object’s contents to change after the object is constructed. The Immutable pattern also avoids the need to synchronize multiple threads of execution that share an object.

Context

⋅ Value objects are objects whose primary purpose is to encapsulate values rather than to provide behavior. For example, the class java.awt.Rectangle encapsulates the position and dimensions of a rectangle.

⋅ In situations where multiple objects share access to the same value object, a problem can arise if changes to the shared object are not properly coordinated between the objects that share it. This coordination can require careful programming that is easy to get wrong. If the changes to and fetches of the shared objects’ state are done asynchronously, then in addition to the greater likelihood of bugs, correctly functioning code will have the overhead of synchronizing the accesses to the shared objects’ state.

Page 27: Design Patterns

173

⋅ The Immutable pattern avoids these problems. It organizes a class so that the state information of its instances never changes after they are constructed.

⋅ Suppose you are designing a multiplayer game program that involves the placement and occasional movement of objects on a playing field. In the course of designing classes for the program, you decide to use immutable objects to represent the position of objects on the playing field. An organization of a class for modeling position is shown in Figure 12.

Figure 12. Immutable position.

⋅ You have a class called Position that has an x and a y value associated with its instances. The class has a constructor that specifies the x and y values. It also has methods to fetch the x and y values associated with its instances, as well as a method that creates a new Position object at a given x and y offset from an existing position. It does not have any methods to modify its x or y values. If an object’s position changes, it will be made to refer to a new position object.

Forces

☺ Your program uses instances of a class that is passive in nature. The instances do not ever need to change their own state. The instances of that class are used by multiple other objects.

☺ Coordinating changes to the contents of a value object used by mul tiple objects can be a source of bugs. When the contents of a value object change, all the objects that use it may need to be informed. Also, when multiple objects use an object, they may attempt to change its state in inconsistent ways.

☺ If multiple threads modify the contents of a value object, the modification operations must be synchronized to ensure the consistency of the contents. The overhead of synchronizing the threads may add an unacceptable overhead to accessing the value object’s contents.

☺ An alternative to modifying the contents of a value object is to replace the entire object with another object that has different contents. Doing so avoids the need for synchronization among threads that only fetch the contents of the value object.

� If there are multiple threads that update the contents of an object, replacing the object instead of updating its contents will not avoid the need for synchronizing the threads that do the updating.

� Replacing a value object with a new value object that contains an updated version of the values in the old object involves copying unchanged values from the old object to the new. If the changes to an object are frequent, or if an object has a large amount of state information associated with it, the cost of replacing value objects may be prohibitive.

Solution

⋅ To avoid having to manage the synchronization of changes to value objects used by multiple other objects, make the shared objects immutable, disallowing any changes to their

Page 28: Design Patterns

174

state after they are constructed. You can accomplish this task by not including any methods, other than constructors, in their class that modify state information. The organization of such a class is shown in Figure 13.

Figure 13. Immutable pattern.

⋅ Notice that the class has accessor methods to get state information but none to set it.

Implementation

⋅ There are two concerns when implementing the Immutable pattern:

� No method, other than a constructor, should modify the values of a class’s instance variables.

� Any method that computes new state information must store the information in a new instance of the same class rather than modifying the existing object’s state.

⋅ One possible unexpected detail of implementing the Immutable pattern is that it usually does not involve declaring variables with the final modifier. The values of final instance variables are normally provided from within their class. However, the values of an immutable object’s instance variables normally are provided by another class that instantiates the object.

Consequences

☺ Since the state of immutable objects never changes, there is no need to write code to manage such changes.

☺ An immutable object is often used as the value of another object’s attribute. If the value of an object’s attribute is an immutable object, then it may not be necessary for access to the value’s attribute to be synchronized. The reason is that Java guarantees that assigning an object reference to a variable is always done as an atomic operation. If the value of a variable is an object reference and one thread updates its value and another fetches its value, the other thread will fetch either the new or the old object reference.

� Operations that would otherwise have changed the state of an object must create a new object. This is an overhead that mutable objects do not incur.

Java API Usage

⋅ Instances of the String class are immutable. The sequence of characters that a String object represents is determined when it is constructed. The String class does not provide any methods for changing the sequence of characters that a String object represents. Methods of the String class, such as toLowerCase and substring, compute a new sequence of characters and then return the new sequence of characters in a new String object.

Page 29: Design Patterns

175

E.4 CREATIONAL, BEHAVIORAL AND STRUCTURAL PATTERNS (REFERENCE)

Read DP_Brief.pdf

E.5 MODEL VIEW CONTROLLER

Synopsis

⋅ The Model View Controller is a behavioral design pattern that is used to divide a component or subsystem into three logical parts — model, view, and controller — making it easier to modify or customize each part.

Context

⋅ A problem that has always faced object-oriented developers is how to code suitably generic components. The problem is especially challenging when a component is complex or flexible in its use.

⋅ Consider a table. The concept of a table could be applied many ways depending on the needs of an application. You can approach a table as a way to store data as a logical structure consisting of cells, rows and columns. However, there are many ways to manage what is stored and how to represent that storage.

⋅ For storage decisions, a table might only allow some forms of data (decimal numbers) or it might permit special operations (such as summing). It might behave like a database table, where rows represent records (groups of data elements representing a single entity) and columns represent fields (a data type with consistent identity and storage among all records). Alternatively, a table might have no restrictions on data storage and no special significance attached to its rows and columns.

⋅ A table could also be presented in a number of ways in an application. It could be visually displayed as a grid, graph, or chart. Or it might have no graphical presence at all. It could even use the same underlying storage to supply information to more than one form of display, such as a grid that updates a chart when a user entered values.

⋅ When there are so many possible ways to use a control like a table, you’re presented with a dilemma. Clearly it would be nice to be able to have some form of reuse, so you would not have to code every new table from scratch. At the same time, it’s hard to imagine just how to code a single component like this to be reusable. An implementation that was too generic would require a great deal of work to modify each time it was used, eliminating many of the benefits of reuse.

Solution

⋅ MVC offers an elegant alternative. It defines a complex element in terms of three logical subunits:

� Model – The element’s state, and means for changing the state

� View – The representation of the element (visual or non-visual)

� Controller – The element’s control functionality, mapping actions on the view to their impact on the model Many businesses today are based on the MVC pattern. Corporate management provides the model, establishing the company purpose and setting up rules that govern how the business grows and functions. The sales and marketing departments provide the view, representing the company and its products to the outside world. Finally, product development and manufacturing represent the controller, taking information from the view and translating it to actions that have impact on the model.

Page 30: Design Patterns

176

⋅ By breaking the element down in this way, each part can be treated independently of the others—or, at least, almost independently. For the element to behave as a whole, each part must properly interface with the other two. The view must be able to send messages to the controller and get information from the model in order to meet its responsibilities. However, MVC offers a substantial benefit: it is possible to easily change parts of the component, making a system using MVC extremely versatile. A table implemented this way can be converted from a grid to a graph representation by changing the view.

⋅ The table example focused on a component, but you can apply the MVC pattern at the architectural level as well. In an MVC component the model handles the component's state, the view represents the component's UI, and the controller performs the component's event handling (or action mapping) functions. At the architectural level, you can translate these features to a subsystem: the model actually represents the business model, the view is the presentation of the model (the face of the data), and the controller defines business actions or operations.

Implementation

Figure 14. MVC Pattern component diagram.

⋅ A component diagram has been used to describe this pattern. Each of the three parts of the MVC pattern is a component that can contain many classes and interfaces.

⋅ Implementing the MVC pattern requires the following components:

� Model – This component contains one or more classes and interfaces that are responsible for maintaining the data model. The state of the model is kept in attributes and the implementation of methods. To be able to notify view components of any change in the model, the model keeps a reference to each registered view (there can be more than one at the same time). When a change occurs, every view component that has registered should be notified.

� View – The classes and interfaces of the view provide a representation of the data in the model component. The view may consist of visual GUI components, but is not required to. A view must be registered with the model to be notified of changes to the model data. When a notification of such a change is received, the view component is responsible for determining if and how to represent this change.

The view component also keeps a reference to the model to retrieve data from the model, but it can only retrieve information, not change it. The view can also be used to render the controller, but requests for change are always forwarded to a controller component; so the view needs to keep a reference to one or more controllers.

Page 31: Design Patterns

177

� Controller – This component manages changes to the model. It keeps a reference to the model component that is responsible for carrying out the change, whereas the controller calls one or more update methods. The requests for change may come from a view component.

Forces

☺ MVC is useful when there is a component or subsystem that has some of the following characteristics:

� It is possible to view the component or subsystem in different ways. The internal representation for the system may be completely different from the representation on a screen.

� There are different possible types of behavior, meaning that multiple sources are allowed to invoke behavior on the same component but the behavior may be different.

� Behavior or representation that changes as the component is used.

� You often want the ability to adapt or reuse such a component under a variety of circumstances with a minimum amount of recoding.

Consequences

☺ MVC is a pattern that encourages good encapsulation. The principles of good object-oriented programming recommend that you define elements in terms of their interface (how they interact with the outside world, other objects, components or systems) and implementation (how they maintain state and function internally). MVC supports this, since it explicitly breaks an element’s responsibilities into:

� Model – The implementation (state: attributes and internal behavior)

� View – The outbound/outgoing interface (behavior: defines the services that can be used to represent the model)

� Controller – The inbound/incoming interface (behavior: accepts request for updates on the model)

☺ MVC provides an excellent way to make an element that is flexible and adaptable to a variety of new situations. The flexibility can be used both statically and dynamically. New view or controller classes can be added to the application (static), and view or controller objects can be changed in the application at runtime.

� Usually, the greatest challenge for MVC is to determine the true base representation; to define a suitable set of interfaces among model, view, and controller. An MVC element is often developed to satisfy a specific set of needs, like most software, so vision and careful analysis are required in order to implement the element so that you don’t impose application-specific restrictions on it.

Pattern Variants

⋅ MVC variants often revolve around different implementation choices for the view.

� Model push versus view pull – You can implement MVC in one of two ways the model can send updates to its view (or views), or a view can retrieve information as needed from the model. The choice affects how the relationship is implemented in the system.

� Multiple view targets – A model can provide information to more than one view. This is particularly useful for some GUI implementations, since the same data must sometimes drive multiple representations.

Page 32: Design Patterns

178

� “Look but don’t touch” views – Not all views require a controller. Some provide only a visual representation of model data, but don’t support any changes to the model from that view.

Related Patterns

⋅ Related patterns include the following:

� Observer – The MVC pattern often uses the Observable pattern to manage communication. This is usually done for the following parts of the system:

- Between the view and controller, so that a change in the view triggers a response in the controller

- Between the model and view, so the view is notified of a change in the model.

� Strategy – The controller is often implemented with the Strategy pattern to simplify changing controllers.

E.6 PATTERNS IN JAVA API

⋅ The Java APIs provide additional demonstrations of pattern use. These real-world patterns provide useful insight into how patterns can be effectively applied to solve problems.

⋅ At this point, it’s worth explaining what exactly is meant by “API”. It's become a somewhat vague term in recent years. These days, API is used to refer to a single class, a group of classes, a single package or a set or related packages. The important quality that defines an API is the fact that it provides a programming framework for a set of related functional capabilities.

⋅ A number of the APIs in Java are actually designed as a set of related classes. To appreciate the way that an API functions as a whole, it makes sense to spend some time discussing its basic structure. This provides a perspective on how patterns support the API – how they help a specific API to better do its job. This provides a few practical benefits:

� It can help you appreciate some of the ways that patterns are actually used within the API. Studying the Java APIs demonstrates how patterns can be applied to achieve practical goals.

� It shows how you can use patterns with the APIs. Examining a set of APIs can help you see how to effectively use a pattern to interact with an API or framework.

� This should give you new insight into their use and usefulness – perhaps even on why they're designed the way they are.

Read DP_Java.pdf

E.7 PATTERNS BY INTENT

⋅ In this chapter we give brief recommendations for the use of some specific patterns using categorization of design patterns by intent. To remind you, a design pattern is a pattern that uses classes and their methods in an object-oriented language. A pattern can be sees as a way to pursue an intent, and the intents can be categorized to five categories:

� Interfaces

� Responsibility

� Construction

� Operations

� Extensions

Page 33: Design Patterns

179

E.7.a Interfaces

⋅ Speaking abstractly, a class’s interface is the collection of methods and fields that a class permits objects of other classes to access. This interface usually represents a commitment that the methods will perform the operation implied by their names and as specified by code comments and other documentation. A class's implementation is the code that lies within its methods.

⋅ Java elevates the notion of interface to be a separate construct, expressly separating interface—what an object must do—from implementation—how an object fulfills this commitment. Java interfaces allow several classes to provide the same functionality, and they open the possibility that a class can implement more than one interface.

⋅ The Java interface construct is a powerful tool worth studying in its own right, but your design intent will sometimes go beyond the simple definition of an interface. For example, you might use an interface to adapt a class's interface to meet a client's needs, applying the Adapter pattern. You might also create an interface to a collection of classes, applying the Facade pattern. In this case, you create a new interface by creating a new class rather than a new interface. In these circumstances and others you can apply design patterns to go beyond the ordinary use of interfaces.

⋅ You can simplify and strengthen your designs with appropriate application of Java interfaces. Sometimes, though, the design of an interface has to go beyond the ordinary definition and use of an interface.

Table 6. Intent of Interface patterns

If you intend to Apply the pattern

Adapt a class's interface to match the interface a client expects Adapter

Provide a simple interface into a collection of classes Facade

Define an interface that applies to individual objects and groups of objects

Composite

Decouple an abstraction from its implementation so that the two can vary independently

Bridge

⋅ The intent of each design pattern is to solve a problem in a context. Interface-oriented patterns address contexts in which you need to define or to redefine access to the methods of a class or a group of classes. For example, when you have classes that performs a service you need but with method names that do not match a client’s expectations, you can apply the Adapter pattern.

E.7.b Responsibility

⋅ Like call center representatives, ordinary objects have the information and methods they need to operate independently. Sometimes, however, you need to centralize responsibility, diverting from the normal independent operation of objects. Several design patterns address this need. Other patterns let objects escalate requests and isolate an object from other objects that depend on it. Responsibility-oriented patterns provide techniques for centralizing, escalating, and limiting ordinary object responsibility.

⋅ Like developers, objects have certain responsibilities but in a different sense. Objects cannot bear a moral, ethical, or professional responsibility, but we do say that object-oriented development distributes responsibility to individual objects. This is primarily a way of characterizing encapsulation, the idea that an object works on its own data. Object-oriented development ordinarily distributes responsibility as far as it will go, meaning that each object does its own work.

Page 34: Design Patterns

180

⋅ Distributed responsibility is the norm, but several design patterns oppose this and move responsibility to an intermediary or to a particular object. A central figure may absorb certain responsibilities, or you may also need policies for escalating requests to other authorities. And, although objects are normally highly responsible, you may want to observe their behavior without their knowing it. You can think of the intent of the Observer pattern and several other patterns as exceptions to the ordinary rule of distributed responsibility.

Table 7. Intent of Responsibility patterns

If you intend to Apply the pattern

Centralize responsibility in a single instance of a class Singleton

Decouple an object from awareness of which other objects depend on it

Observer

Centralize responsibility in a class that oversees how a set of other objects interact

Mediator

Let an object act on behalf of another object Proxy

Allow a request to escalate up a chain of objects until one handles it Chain of Responsibility

Centralize responsibility in shared, fine-grained objects Flyweight

⋅ The intent of each design pattern is to solve a problem in a context. Responsibility-oriented patterns address contexts in which you need to deviate from the normal rule that responsibility should be distributed as far as possible. For example, when you need to centralize responsibility in a single instance of a class, you can apply the Singleton pattern.

E.7.c Construction

⋅ When you create a Java class, you normally provide for the creation of objects of your class by supplying class constructors. In many regards, constructors are like any other methods, but Java has numerous rules that specifically govern the use of constructors. In particular, constructors have special abilities to collaborate with one another.

⋅ Eventually, a constructor always collaborates with one of its superclass's constructors. If a class has no declared constructor, Java supplies a default one equivalent to a constructor with no arguments and no statements. If the first statement in a constructor is anything other than a specific invocation of another constructor, Java inserts a call to super(), the superclass's constructor with no arguments. This causes a compilation error if the superclass does not provide a constructor with no arguments.

⋅ Java will not always insert a call to super() in a constructor. A constructor can avoid this default behavior by explicitly invoking a superclass constructor or by invoking another constructor of the current class with a call to this(). When a class has several constructors, they usually apply calls to this() to collaborate with one another.

⋅ Java's constructor features provide many alternatives when you design a new class. However, constructors are effective only if the user of your class knows which class to instantiate and knows the required fields for instantiating an object. For example, the choice of which user interface component to compose may depend on whether the program is running on a handheld device or on a larger display. It can also happen that a developer knows which class to instantiate but does not have all the necessary initial values or has them in the wrong format. For example, the developer may need to create an object from a dormant or a textual version of an object. In such circumstances, you need to go beyond the use of ordinary Java constructors and apply a design pattern.

⋅ The following principles describe the intent of patterns that facilitate construction.

Page 35: Design Patterns

181

Table 8. Intent of Responsibility patterns

If you intend to Apply the pattern

Gather the information for an object gradually before requesting its construction

Builder

Defer the decision of which class to instantiate Factory Method

Construct a family of objects that share a trait Abstract Factory

Specify an object to create by giving an example Prototype

Reconstruct an object from a dormant version that contains

just the object's internal state

Memento

⋅ The intent of each design pattern is to solve a problem in a context. Construction-oriented

patterns are designs that let a client construct a new object through a means other than calling a class constructor. For example, when you find the initial values for an object gradually, you may want to follow the Builder pattern.

E.7.d Operations

⋅ When you write a Java method, you produce a fundamental unit of work that is a level up from writing a statement. Your methods have to participate in an overall design, architecture, and test plan, but no activity is more central to programming than writing methods. Ironically, despite the central role of methods, it is easy to get confused about what methods are and how they function. You need to be aware of a few syntactic subtleties in Java methods. But more confusing is the tendency of many developers and authors to slosh together the meaning of the words method, operation, and algorithm. By distinguishing the meanings of these terms, you can express important concepts that surface in many design patterns.

⋅ Having a clear understanding of what methods are will also help you understand several design patterns. In particular, State, Strategy, and Interpreter all work by implementing an operation in methods across several classes, but such observations are useful only if we agree on the meaning of method and operation.

⋅ It is useful to distinguish operation from method and to then discuss these concepts' relations to algorithm.

� An operation is a specification of a service that can be requested from an instance of a class.

� A method is an implementation of an operation.

� An algorithm is any well-defined computational procedure that takes some value, or set of values, as input and produces some value, or set of values, as output. Algorithms get something done. They may appear as part of a method, or they may involve many methods. For example, the isTree() algorithm four methods, as Figure 15. Algorithms that require more than one method often rely on polymorphism to allow multiple implementations of a single operation.

� Polymorphism is the principle that method invocation depends on both the operation invoked and the class of the invocation receiver.

Page 36: Design Patterns

182

Figure 15. Four isTree() methods collaborate to effect the algorithm for determining whether an instance of MachineComponent is a tree.

⋅ The word operation applies when talking about the idea that many methods may have the same interface. The word signature applies when discussing method lookup rules. A method definition includes its signature —its name and parameter list—along with modifiers, return type, a throws clause, and the method's body. A method has a signature and implements an operation. An algorithm is a procedure that accepts inputs and produces outputs. Methods accept inputs, produce outputs, and contain a procedural method body, so it is common to refer to a method as an algorithm. However, an algorithm's procedure may involve many operations and methods, or it may exist as part of another method. The word algorithm best applies when you are discussing a procedure that produces a result.

⋅ Many design patterns involve distributing an operation across several classes. You can also say that these patterns rely on polymorphism, the principle that method selection depends on the class of the object that receives a method call. The decision of which method executes depends on many rules and various aspects of method headers. In particular, it is important to understand that the static modifier means that the decision of which method to execute depends on the receiver's declared type, not the class of the object.

⋅ Methods execute until they return, unless they produce an exception. The potential for some exceptions is so commonplace that methods need not declare them. Other, checked exceptions must appear in a method's throws clause. The decision of whether an exception should be checked or unchecked is a matter of judgment.

⋅ Different classes can implement an operation in different ways. In other words, Java supports polymorphism. The power of this seemingly simple idea appears in several design patterns.

Table 9. Intent of Operations.

If you intend to Apply the pattern

Implement an algorithm in a method, deferring the definition

of some steps of the algorithm so that subclasses can redefine

them

Template Method

Distribute an operation so that each class represents a

different state

State

Encapsulate an operation, making implementations

interchangeable

Strategy

Encapsulate a method call in an object Command

Distribute an operation so that each implementation applies

to a different type of composition

Interpreter

Page 37: Design Patterns

183

⋅ Operation-oriented patterns address contexts in which you need more than one method, usually with the same signature, to participate in a design. For example, the Template Method pattern allows subclasses to implement methods that adjust the effect of a procedure defined in a superclass.

E.7.e Extensions

⋅ An extension is the addition of a class, an interface, or a method to an existing code base. The most common way to extend code is to write a new class, although you can also extend a class through delegation. In particular, when you'd like to subclass from two parents, you can subclass from one parent and use delegation to "inherit" the behavior of the other class.

⋅ Object-oriented development in Java does not begin from scratch. Rather, it's fair to say that object-oriented software development is extension. To develop in Java, learn what is available in an existing code base, including a company's code and the Java class libraries. After seeing where your changes fit in, add the code you need for your application. In Java, application development is extension, and extension begins where reuse leaves off.

⋅ One way to extend the application is to create new classes by inheriting them from the existing ones. The subclasses you create should be logical and consistent extensions of their superclasses. A Java compiler will ensure a certain level of consistency, but many principles of consistency will elude a compiler. One principle you should consider in your designs is the Liskov Substitution Principle (LSP). This principle, documented in Liskov (1987), can be paraphrased: “An instance of a class should function as an instance of its superclass”. Basic LSP compliance is built into OO languages, such as Java. However, some aspects of LSP compliance require human-level intelligence, or at least more intelligence than today's compilers possess.

⋅ Another way is to use extension through delegation, which occurs when a class has methods that forward calls to identical operations supplied by another object. This technique makes available the behavior of the forwarded-to class on the class you are extending, but this is usually not the best way to achieve extension. If you want to inherit the exact methods of an existing class, the most straightforward approach is to subclass it. However, this is not always possible. The class whose behavior you need may be declared final—as String is, for example—or your class may already be subclassing something else. In these cases, you can extend your class through delegation.

⋅ A major change that has accompanied the advent of object-oriented programming is that programming is now a matter of extending an existing code base. Talented Java developers spend more time reading than writing, to understand how their code will fit with and benefit from the voluminous class libraries. One class that you should be especially sure to understand is Object, the superclass from which all your classes will derive.

⋅ A healthy view is that development is a matter of extending the Java code base with just the changes you need for your application. Aggressive reuse of the Java class libraries will you help you reduce the chances for introducing defects and will let you benefit from the hard work of many developers who have preceded you. With a good understanding of the existing code base, you can develop rich applications as minimal extensions of existing code.

⋅ The ordinary way to extend a software system is to find a suitable superclass—usually Object—and to subclass it. You can also "inherit" behavior from more than one class by copying some of the operations of a second class and delegating calls to an instance of that class. Both of these extension techniques, however, require that you know at compile time what behaviors you want to add. If you need to add behavior to an object without changing its class, you may be able to apply the Template Method, Command, Decorator, Visitor design patterns.

Page 38: Design Patterns

184

⋅ Ordinary extension also adds behavior to individual instances of a class. You may need to add behaviors that apply to a collection of instances of your class. The Iterator pattern addresses one such case.

Table 10. Intent of Operations

If you intend to Apply the pattern

Allow a client to hook in an operation at a step in an algorithm Template Method

Let a client outfit your code with an operation to execute in

response to an event

Command

Attach additional responsibilities to an object dynamically Decorator

Provide a way to access a collection of instances of a class

that you create

Iterator

Allow for the addition of new operations to a class without

changing the class

Visitor

⋅ Extension-oriented patterns address contexts in which you need to add behavior specific to

a collection of objects or to add new behaviors to an object without altering the object's class. For example, when you need to be able to add new behavior to an object dynamically, you can apply the Decorator pattern.

E.8 RESOURCES

The text above is adopted from the following references: ⋅ Stephen A. Stelting, Olav Maassen, Applied Java Patterns, Prentice Hall PTR; 1st edition (December 31,

2001)

⋅ Steven John Metsker, Design Patterns Java Workbook, Addison-Wesley Professional; 1st edition (March 25, 2002)

⋅ Partha Kuchana, Software Architecture Design Patterns in Java, Auerbach Publications (April 22, 2004)

⋅ Mark Grand, Patterns in Java, Volume 1: A Catalog of Reusable Design Patterns Illustrated with UML, Second Edition, John Wiley & Sons (2002).

⋅ Liskov, Barbara. “Data Abstraction and Hierarchy”. SIGPLAN Notices, vol. 23, no 5, Special issue: OOPSLA '87, pp. 17-34 (May, 1987).