The Gang of Four (GoF) patterns are generally considered the foundation for all other patterns. They are categorized in three groups: Creational, Structural, and Behavioral. Here you will find information on these important 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
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 cans 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.
Creational Patterns
1. Abstract Factory Creates an instance of several families of classes
2. Builder Separates object construction from its representation
3. Factory Method Creates an instance of several derived classes
4. Prototype A fully initialized instance to be copied or cloned
5. Singleton A class of which only a single instance can exist
Structural Patterns
6. Adapter Match interfaces of different classes
7. Bridge Separates an object’s interface from its implementation
8. Composite A tree structure of simple and composite objects
9. Decorator Add responsibilities to objects dynamically
10. Facade A single class that represents an entire subsystem
11. Flyweight A fine-grained instance used for efficient sharing
12. Proxy An object representing another object
Behavioral Patterns
13. Chain of Resp. A way of passing a request between a chain of objects
14. Command Encapsulate a command request as an object
15. Interpreter A way to include language elements in a program
16. Iterator Sequentially access the elements of a collection
17. Mediator Defines simplified communication between classes
18. Memento Capture and restore an object's internal state
19. Observer A way of notifying change to a number of classes
20. State Alter an object's behavior when its state changes
21. Strategy Encapsulates an algorithm inside a class
22. Template Method Defer the exact steps of an algorithm to a subclass
23. Visitor Defines a new operation to a class without change
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.
8. Open Session in View pattern: Using the Filter & creating the single session and transaction each web request.
What major patterns do the Java APIs utilize?
Design patterns are used and supported extensively throughout the Java APIs. Here are some examples:1. The Model-View-Controller design pattern is used extensively throughout the Swing API.
2. The getInstance() method in java.util.Calendar is an example of a simple form of the Factory Method design pattern.
3. 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.
4. The Prototype pattern - Cloning an object by reducing the cost of creation.
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.
5. The Java Swing classes support the Command pattern by providing an Action interface and an AbstractAction class.
6. 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.
7. The Adapter pattern is used extensively by the adapter classes in java.awt.event.
8. The Proxy pattern is used extensively in the implementation of Java's Remote Method Invocation (RMI) and Interface Definition Language (IDL) features.
9. The structure of Component and Container classes in java.awt provide a good example of the Composite pattern.
10. 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.
Front Controller | Dicription | The Front Controller pattern defines a single component that is responsible for processing application requests. A front controller centralizes functions such as view selection, security, and templating, and applies them consistently across all pages or views. Consequently, when the behavior of these functions need to change, only a small part of the application needs to be changed: the controller and its helper classes. |
Advantage | Promotes a centralized management system and removes code duplicacy; Centralized system may be useful to control and log a user's progress through the site; Promotes code reuse across requests; Improves manageability of security; Configurability - Only one front controller needs to be configured into the Web server; the handler does the rest of the dispatching. This simplifies the configuration of the Web server. | |
Disadvantage | Performance considerations. Front Controller is a single controller that handles all requests for the Web application. Of the two parts, the handler should be examined closely for performance problems, because the handler determines the type of command that performs the request. If the handler must perform a database query or a query of an XML document to make the decision, performance could be very slow as a result. Increased complexity. Front Controller is more complicated than Page Controller. It often involves replacing the built-in controller with a custom built Front Controller. Implementing this solution increases the maintenance costs and the time it takes for developers to orient themselves to the solution. | |
Alternatives | Embed code in multiple views i.e. a distributed model like a Page Controller; Intercepting filter pattern | |
Comparison | Intercepting filters are used when the request/response needs to be modified. Front Controller is mainly used to determine processing based on the request without modifying it. | |
Factory | Dicription | It deals with the problem of creating objects (products) without specifying the exact class of object that will be created. The factory method design pattern handles this problem by defining a separate method for creating the objects, which subclasses can then override to specify the derived type of product that will be created |
Advantage | The factory decouples the calling class from the target class. E.g. Obtaining DB connection for different databases | |
Disadvantage | Adding a new object to be returned requires change to the Factory class itself. | |
Alternatives | Using reflection mechanism | |
Comparison | Reflection is not provided by all languages; Use of relfection mechanism causes a performance hit of upto 10% as compared to non reflection mechanism. | |
Singleton | Dicription | The job of the Singleton class is to enforce the existence of a maximum of one object of the same type at any given time |
Advantage | Maintain single instance and helps in preserving resources. E.g. Connection object to connect to DB | |
Disadvantage | If the Singleton has synchronized blocks in it, you'll have threads in your system fighting for the locks on your Singleton. This might slow your system down as the threads fight for access to the resources. Difficult to judge whether we are working on a single instance of the intended object or not. | |
Alternatives | Use dependency injection | |
Comparison |
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...
}
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
1. It is directly supported by object-oriented languages, and
2. 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 cans 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.