CSC/ECE 517 Fall 2012/ch2b 2w35 av
Introduction
One of the most complex tasks in creating a software is designing it to meet the needs of the user. Designing an object-oriented components of software that is reusable is hard. One must find pertinent objects, factor them into classes at the right granularity, define class interfaces and inheritance hierarchies, and establish key relationships among them. It should also be taken care that the design is specific to a problem at hand and also general enough to accommodate future changes. Knowledge of design patterns helps in such scenarios. Essentially, Design patterns describe a problem which occurs over and over again in an environment, and then describes the core of the solution to that problem, in such a way that one can use this solution a million times over, without ever doing it the same way twice
Classes of Design Patterns
Design patterns are generally classified into the one of the following three categories.
Creational Pattern, which help create the objects for the user, instead of having the user to instantiate the object.
Structural Pattern, which employ interfaces to achieve inheritance to enable objects to obtain new functionality.
Behavioral Pattern, which are concerned with communication between objects.
Builder Pattern
The intent of Builder pattern is to separate the construction of a complex object from its representation so that the same construction process can create different representations. According to GOF [1], the builder pattern can be applied when
1. The algorithm for creating a complex object should be independent of the parts that make up the object and how they're assembled.
2. The construction process must allow different representations for the object that's constructed.
Let us consider an example for builder pattern. Consider a word processing software that should have the ability to convert Microsoft word's DOC to many text formats. The reader might convert *.DOC documents into plain ASCII text or into a PDF. The problem, however, is that the number of possible conversions is open-ended. So it should be easy to add a new conversion without modifying the reader.
A solution is to configure the DOCReader class with a TextConverter object that converts DOC to another textual representation. As the DOCReader parses the DOC document, it uses the TextConverter to perform the conversion. Whenever the DOCReader recognizes an DOC token (either plain text or an RTF control word), it issues a request to the TextConverter to convert the token. TextConverter objects are responsible both for performing the data conversion and for representing the token in a particular format. Subclasses of TextConverter specialize in different conversions and formats. For example, an PlainTextConverter ignores requests to convert anything except plain text. A LaTeXConverter, on the other hand, will implement operations for all requests in order to produce a LaTeX representation that captures all the stylistic information in the text.
Each kind of converter class takes the mechanism for creating and assembling a complex object and puts it behind an abstract interface. The converter is separate from the reader, which is responsible for parsing an DOC document. Converter class designed as discussed above basically defines the builder design pattern.
Abstract Factory
Abstract factory method, also known as Kit, provide an interface for creating families of related or dependent objects without specifying their concrete classes. The major difference between Abstract factory and builder pattern is that the focus with builder pattern is on 'step-by-step' object creation but with abstract factory, there is no step by step object creation. The object that is being created is usually created immediately and returned to the caller. The client software creates a concrete implementation of the abstract factory class and then uses the generic interfaces defined by the abstract factory to create the concrete objects according to the requirement<ref>Abstract Factory Wiki</ref>.
Consider a case where we need to define a different look and feel for different operating systems or profiles. Hard coding them into each type can result in code duplication and also a poor quality code. This is where abstract factory pattern comes to use. A common factory class can be created for declaring an interface for creating each look and feel. Then, a concrete class can be created for each type of look and feel that we want and just implementing the required effects in the interfaces. An example of using Abstract factory to define different widget interfaces is shown here.
Here in this example, the MotifWidgetFactory has its own implementation of the createScrollBar and createWindow functions that instantiate MotifWindow and MotifScrollBar. This allows any number of newer types of objects to be created by just extending the abstract class and implementing the desired features. The clients call these operations to obtain the widget instances, but they'll never know which concrete classes have been used to create them. All the operations that are done by the client is done using the Abstract factory interface.
Abstract factory pattern helps in achieving the following,
- a system should be independent of how its products are created, composed, and represented.
- a system should be configured with one of multiple families of products.
- a family of related product objects is designed to be used together, and you need to enforce this constraint.
- you want to provide a class library of products, and you want to reveal just their interfaces, not their implementations
References
<references/>