|
1)What
is a software design pattern?
A
design pattern is a solution to a general software
problem within a particular context.
- Context
- A recurring set of situations where the pattern applies.
- Problem
- A system of forces (goals and constraints) that
occur repeatedly in this context.
- Solution
- A description of
communicating objects and classes (collaboration) that can be applied to
resolve those forces.
Design
patterns capture solutions that have evolved over time as developers strive for
greater flexibility in their software. Whereas class libraries are reusable
source code, and components are reusable packaged objects, patterns are generic,
reusable design descriptions that are customized to solve a specific problem.
The study of design patterns provides a common vocabulary for communication and
documentation, and it provides a framework for evolution and improvement of
existing
patterns. 2)Why
is the study of patterns important?
As
initial software designs are implemented and deployed, programmers often
discover improvements which make the designs more adaptable to change. Design
patterns capture solutions that have evolved over time as developers strive for
greater flexibility in their software, and they document the solutions in a way
which facilitates their reuse in other, possibly unrelated systems. Design
patterns allow us to reuse the knowledge of experienced software designers.
Moreover, the study of design patterns provides a common vocabulary for
communication and documentation, and it provides a framework for evolution and
improvement of existing patterns. As an analogy, consider that during a
discussion among programmers, the words “stack” and “tree” can be used freely
without explanation. Software developers understand fundamental data structures
such as a “stack” because these data structures are well-documented in textbooks
and are taught in computer science courses. The study of design patterns will
have a similar (but more profound) effect by allowing designers to say
“composite pattern” or “observer pattern” in a particular design context,
without having to describe all classes, relationships, and collaborations which
make up the pattern. Patterns raise the level of abstraction when discussing and
documenting software designs.
3)How
do I document a design pattern?
A
pattern description must address the following major points:
- Pattern Name and Classification
- A short, meaningful name for the
pattern, usually only one or two words. Names provide a vocabulary for
patterns, and they have implied semantics – choose names carefully. Following
the GoF book, we can also group patterns into higher level classifications
such as creational, structural, and behavioral patterns.
- Problem
- A general description of the problem context and the goals and
constraints that occur repeatedly in that context. A concrete motivational
scenario can be used to help describe the problem. The problem description
should provide guidance to assist others in recognizing situations where the
pattern can be applied.
- Solution
- The classes and/or objects
that participate in the design pattern, their structure (e.g., in terms of a
UML class diagram), their responsibilities, and their collaborations. The
solution provides an abstract description that can be applied in many
different situations. Sample Code in an object-oriented language can be used
to illustrate a concrete realization of the pattern.
- Consequences
- A discussion of the results and tradeoffs of applying the pattern.
Variations and language-dependent alternatives should also be addressed.
- Known Uses
- Examples of the pattern in real systems. Look for
applications of the pattern in language libraries and frameworks, published
system descriptions, text books, etc. Not every good solution represents a
pattern. A general rule of thumb is that a candidate pattern (also called a
“proto-pattern”) should be discovered in a minimum of three existing systems
before it can rightfully be called a pattern.
The
following quote by Robert Martin highlights the importance of providing pattern
descriptions: “The revolutionary concept of the GoF book is not the fact that
there are patterns; it is the way in which those patterns are documented. ...
Prior to the GoF book, the only good way to learn patterns was to discover them
in design documentation, or (more probably) code.”
4)Where
can I learn more about design patterns?
The
best place to start is the seminal work by Erich Gamma, Richard Helm, Ralph
Johnson, and John Vlissides (collectively known as the “Gang of Four” or simply
“GoF”) entitled
Design
Patterns: Elements of Reusable Object-Oriented Software (Addison-Wesley,
1995).
Warning: This book is not light reading. From the Preface:
“Don't worry if you don't understand this book completely on the first reading.
We didn't understand it all on the first writing.”
It is, however, a book which wears well over time, and it is definitely worth
the effort required to work through it.
Beyond the GoF book, consider the list of references in the Design Patterns
section of this
bibliography on object technology, plus the following web links:
Design Patterns Home Page
Huston Design
Patterns
Brad Appleton's
Software Patterns Links
Cetus Patterns Links
5)What
is an example of a design pattern?
Following
the lead of the “Gang of Four” (GoF), design pattern descriptions usually
contain multiple sections including
-
Intent
-
Motivation
-
Applicability
-
Structure
-
Participants
-
Collaborations
-
Consequences
-
Implementation
-
Sample Code
-
Known Uses
-
Related Patterns
A
complete discussion of even a small pattern is beyond the scope of a simple FAQ
entry, but it is possible to get the idea by examining an abbreviated discussion
of one of the simplest and most easily understood patterns. Consider the
Singleton pattern, whose intent reads as follows:
Intent:
Ensure that a class has one instance, and provide a global point of access to
it.
Almost
every programmer has encountered this problem and formulated an approach for
solving it in a general way – some solutions are better than others. The
solution offered by the GoF would look something like the following when coded
in Java.
public class Singleton { private static Singleton instance = null;
public static Singleton getInstance() { if (instance == null) instance = new Singleton(); return instance; }
protected Singleton() { ... } // possibly another constructor form
public void someMethod() { ... }
//... other methods }
The
programmer would access the single instance of this class by writing something
similar to
Singleton.getInstance().someMethod()
or
similar to
Singleton s = Singleton.getInstance(); s.method1(); ... s.method2(); ...
For
a more complete discussion of the Singleton pattern, see the chapter “Singleton”
in the book
Design Patterns: Elements of Reusable Object-Oriented Software by the
“Gang of Four” (Addison-Wesley, 1995), or the chapter “Singleton” in the book
Patterns in Java, Volume 1 by Mark Grand (John Wiley & Sons,
1998). For information about variations on the Singleton Pattern, see the
chapter entitled “To Kill a Singleton” in the book
Pattern Hatching: Design Patterns Applied by John Vlissides or the
article
“Implementing the Singleton Pattern in Java” by Rod
Waldhoff.
6)Calendar
is an abstract class. The getInstance() method tries to instantiate
GregorianCalendar() i.e., parent instantiating a derived class. This looks
Non-OO? Ex: Calendar a=Calendar.getInstance(); Can somebody explain why is it
so?
The
Calender class is an abstact class, true, however,the point you missed is that
the getInstance() returns the " Calendar using the default timezone and locale.
" , in your case, the GregorianCalender a class that IS a Calender (a Suzuki IS
a car, a 747 IS a plane..the standard OO terminology. So what you get is a class
that does some specialized work based on the default locale. Other methods
public static synchronized Calendar getInstance(TimeZone zone,Locale aLocale) public static synchronized Calendar getInstance(TimeZone zone)
return
Calenders for specific timezones and locales. The closest parallel is possibly
the Factory Method design pattern.
7)What
major patterns do the Java APIs utilize?
Design
patterns are used and supported extensively throughout the Java APIs. Here are
some examples:
-
The Model-View-Controller design pattern is used extensively throughout the
Swing API.
-
The getInstance() method in java.util.Calendar is an example of a simple
form of the Factory Method design pattern.
-
The classes java.lang.System and java.sql.DriverManager are examples of the
Singleton pattern, although they are not implemented using the approach
recommended in the GoF book but with static methods.
-
The Prototype pattern is supported in Java through the clone() method
defined in class Object and the use of java.lang.Cloneable interface to
grant permission for cloning.
-
The Java Swing classes support the Command pattern by providing an Action
interface and an AbstractAction class.
-
The Java 1.1 event model is based on the observer pattern. In addition, the
interface java.util.Observable and the class java.util.Observer provide
support for this pattern.
-
The Adapter pattern is used extensively by the adapter classes in
java.awt.event.
-
The Proxy pattern is used extensively in the implementation of Java's Remote
Method Invocation (RMI) and Interface Definition Language (IDL) features.
-
The structure of Component and Container classes in java.awt provide a good
example of the Composite pattern.
-
The Bridge pattern can be found in the separation of the components in
java.awt (e.g., Button and List), and their counterparts in java.awt.peer.
8)How
can I make sure at most one instance of my class is ever created?
This
is an instance where the Singleton design pattern would be used. You need to
make the constructor private (so nobody can create an instance) and provide a
static method to get the sole instance, where the first time the instance is
retrieved it is created:
public class Mine { private static Mine singleton; private Mine() { } public static synchronized Mine getInstance() { if (singleton == null) { singleton = new Mine(); } return singleton; } // other stuff... }
9)When
would I use the delegation pattern instead of inheritence to extend a class's
behavior?
Both
delegation and inheritance are important concepts in object-oriented software
design, but not everyone would label them as patterns. In particular, the
seminal book on design patterns by the “Gang of Four” contains a discussion of
inheritance and delegation, but the authors do not treat these topics as
specific patterns. It is reasonable to think of them as design concepts which
are more general than specific design patterns.
Inheritance is a relationship between two classes where one class, called a
subclass in this context, inherits the attributes and operations of another
class, called its superclass. Inheritance can be a powerful design/reuse
technique, especially when it is used in the context of the Liskov Substitution
Principle. (The article by Robert Martin at
http://www.objectmentor.com/publications/lsp.pdf provides an excellent
explanation of the ideas behind Barbara Liskov’s original paper on using
inheritance correctly.) The primary advantages of inheritance are
-
it is directly supported by object-oriented languages, and
-
it provides the context for polymorphism in strongly-typed object-oriented
languages such as C++ and Java.
But
since the inheritance relationship is defined at compile-time, a class can’t
change its superclass dynamically during program execution. Moreover,
modifications to a superclass automatically propagate to the subclass, providing
a two-edged sword for software maintenance and reuse. In summary, inheritance
creates a strong, static coupling between a superclass and its subclasses.
Delegation can be viewed as a relationship between objects where one object
forwards certain method calls to another object, called its delegate. Delegation
can also a powerful design/reuse technique. The primary advantage of delegation
is run-time flexibility – the delegate can easily be changed at run-time. But
unlike inheritance, delegation is not directly supported by most popular
object-oriented languages, and it doesn’t facilitate dynamic polymorphism.
As a simple example, consider the relationship between a Rectangle class and a
Window class. With inheritance, a Window class would inherit its
rectangular properties from class Rectangle. With delegation, a Window
object would maintain a reference or pointer to a Rectangle object, and calls to
rectangle-like methods of the Window object would be delegated to corresponding
methods of the Rectangle object.
Now let’s consider a slightly more complex example. Suppose employees can
classified based on how they are paid; e.g., hourly or salaried. Using
inheritance, we might design three classes: an Employee class which encapsulates
the functionality common to all employees, and two subclasses HourlyEmployee and
SalariedEmployee which encapsulates pay-specific details. While this design
might be suitable for some applications, we would encounter problems in a
scenario where a person changes, say from hourly to salaried. The class of an
object and the inheritance relationship are both static, and objects can’t
change their class easily (but see the State pattern for tips on how to fake
it).
A more flexible design would involve delegation – an Employee object could
delegate pay-related method calls to an object whose responsibilities focused
solely on how the employee is paid. In fact, we might still use inheritance here
in a slightly different manner by creating an abstract class (or interface)
called PayClassification with two subclasses HourlyPayClassification and
SalariedPayClassification which implement classification-specific computations.
Using delegation as shown, it would be much easier to change the pay
classification of an existing Employee object.
This second example illustrates an important point: In implementing delegation,
we often want the capability to replace the delegate with another object,
possibly of a different class. Therefore delegation will often use inheritance
and polymorphism, with classes of potential delegates being subclasses of an
abstract class which encapsulates general delegate responsibilities.
One final point. Sometimes, the choice between delegation and inheritance is
driven by external factors such as programming language support for multiple
inheritance or design constraints requiring polymorphism. Consider threads in
Java. You can associate a class with a thread in one of two ways: either by
extending (inheriting) directly from class Thread, or by implementing the
Runnable interface and then delegating to a Thread object. Often the approach
taken is based on the restriction in Java that a class can only extend one class
(i.e., Java does not support multiple inheritance). If the class you want to
associate with a thread already extends some other class in the design, then you
would have to use delegation; otherwise, extending class Thread would usually be
the simpler approach.
10)Which
patterns were used by Sun in designing the Enterprise JavaBeans
model?
Many
design patterns were used in EJB, and some of them are clearly identifiable by
their naming convention. Here are several:
1.
Factory Method: Define a interface for creating classes, let a subclass (or a
helper class) decide which class to instantiate.
This
is used in EJB creation model. EJBHome defines an interface for creating the
EJBObject implementations. They are actually created by a generated container
class. See InitialContextFactory interface that returns an InitialContext
based on a properties hashtable.
2.Singleton:
Ensure a class has only one instance, and provide a global point of access to
it.
There
are many such classes. One example is javax.naming.NamingManager
3.
Abstract Factory: Provide an interface for creating families of relegated or
dependent objects without specifying their concrete classes.
We
have interfaces called InitialContext, InitialContextFactory.
InitialContextFactory has methods to get InitialContext.
4.Builder:
Separate the construction of a complex factory from its representation so that
the same construction process can create different
representations.
InitialContextFactoryBuilder
can create a InitialContextFactory.
5.
Adapter: Convert the interface of a class into another interface clients
expect.
In
the EJB implementation model, we implement an EJB in a class that extends
SessionBean or a EntityBean. We don't directly implement the EJBObject/home
interfaces. EJB container generates a class that adapts the EJBObject
interface by forwarding the calls to the enterprise bean class and provides
declarative transaction, persistence support.
6.
Proxy: Provide a surrogate for other object to control access to
it.
We
have remote RMI-CORBA proxies for the EJB's.
7.
Memento: Without violating encapsulation, capture and externalize an object's
internal state so that the object can be restored to this state
later.
Certainly
this pattern is used in activating/passivating the enterprise beans by the
container/server.
java6 ejb3 jsf hibernate eclipse ajax groovy spring seam java struts webservice j2me guice java5 jca tapestry soa linux ria books
|