CSC/ECE 517 Fall 2012/ch2b 2w36 av: Difference between revisions
No edit summary |
No edit summary |
||
Line 54: | Line 54: | ||
[[File:Template_method_implementation_-_uml_class_diagram.gif|650 px|thumb|right|UML Diagram for factory method pattern <ref name="ootemplate" /> ]] | [[File:Template_method_implementation_-_uml_class_diagram.gif|650 px|thumb|right|UML Diagram for factory method pattern <ref name="ootemplate" /> ]] | ||
In the UML diagram on the right, abstract primitive operations are defined for which the subclasses provide the implementation. Template method is implemented which specifies the structure of the algorithm. The primitive operations are called within this template method. The ConcreteClass provides subclass specific implementation for the primitive operations. | In the UML diagram on the right, abstract primitive operations are defined for which the subclasses provide the implementation. Template method is implemented which specifies the structure of the algorithm. The primitive operations are called within this template method. The ConcreteClass provides subclass specific implementation for the primitive operations. | ||
Revision as of 23:57, 16 November 2012
Factory Method pattern and the related patterns (Template, Prototype)
Factory Method
Factory method pattern is an Object Oriented Programming concept in which objects can be created without specifying the class to which they belong.Factory method pattern implement the concept of using an object to generate other objects.<ref name="web">http://www.oodesign.com/factory-pattern.html
</ref>Factory method is thus a type of creational pattern. An interface is defined for object creation. However the subclasses decide which class they want to instantiate. Factory methods thus abstract object instantiation from the client.<ref name="userpagesfactory">http://userpages.umbc.edu/~tarr/dp/lectures/Factory.pdf
</ref>
The new operator is used in languages like Java to create an object. However in this case the object creation details are not encapsulated. Factory method allows a client to request for an object so that the object creation is encapsulated. Factory method uses inheritance for object creation. The superclass has ‘placeholders’ for the steps involved in object creation. The actual details of the object creation are specified in the subclass.<ref name="sourcemakingfact">http://sourcemaking.com/design_patterns/factory_method
</ref>
Use of factory method pattern makes the code more flexible to change. In factory method pattern, interface is used to create an object and the actual instantiation of objects is deferred to subclasses that implement this interface. New classes can be added that implement this interface. In this way it becomes easy to add new concrete classes with minimal changes to the classes that use these objects.[head_first_design_pattern]. Factory method can be used when a class does not know the type of objects that it needs to create. <ref name="userpagesfactory" />
UML Diagram for Factory Method Pattern
In the UML diagram on the right, Product is the interface for the type of object created by the factory method. The Product interface is implemented by ConcreteProduct. The factory method which returns an object of type Product, is declared in Creator. The factory method is overridden inside ConcreteCreator to return an instance of ConcreteProduct.
Code Example
This example has been taken from <ref name="sourcemakingfact" />
public interface ImageReader { public DecodedImage getDecodedImage(); } public class GifReader implements ImageReader { public GifReader( InputStream in ) { // check that it's a gif, throw exception if it's not, then if it is decode it. } public DecodedImage getDecodedImage() { return decodedImage; } } public class JpegReader implements ImageReader { //... }
In the example above the ImageReader interface is defined. In this interface, a method getDecodedImage is defined that should return a decoded image. However this image may have been encoded in any format for example GIFF or JPEG. Therefore the functionality of actually decoding the image is implemented inside two classes GifReader and JpegReader . In this way, the responsibility of creating objects decoded in the appropriate format has been delegated to the subclass implementing the interface.
Template Pattern
Template method pattern is used to specify the format of an algorithm. The basic skeleton of an algorithm is defined in the base class using abstract operations. Subclasses override these abstract operations in order to provide concrete behaviour. In this way, two different subclasses may have different implementations of the abstract functions, but the overall structure of the algorithm will remain same.<ref name="ootemplate">http://www.oodesign.com/template-method-pattern.html
</ref>Template method pattern is a behavioural design pattern.<ref name="wikitemplate">http://en.wikipedia.org/wiki/Template_method_pattern
</ref> Template method pattern helps to avoid code duplication and aids in code reuse.<ref name="userpagestemp">http://userpages.umbc.edu/~tarr/dp/lectures/Template.pdf
</ref>
UML Diagram for Template Method Pattern
In the UML diagram on the right, abstract primitive operations are defined for which the subclasses provide the implementation. Template method is implemented which specifies the structure of the algorithm. The primitive operations are called within this template method. The ConcreteClass provides subclass specific implementation for the primitive operations.
Code Example
This example has been taken from <ref name="userpagestemp" />
public abstract class TextDocument { public final void printPage () { Document document = createDocument(); document.printTextHeader(); System.out.println(document.body()); document.printTextFooter(); } public abstract Document createDocument(); public abstract void printTextHeader(); public abstract void printTextFooter(); ... }
public class PlainTextDocumentBuilder extends TextDocument { public PlainTextDocumentBuilder(InputStream in){ //check that it is an Plain text document or throw error } public Document createDocument() { return new PlainTextDocument(); } public void printTextHeader () { // Code for header plain text header here. } public void printTextFooter () { // Code for header plain text footer here. } ... }
public class HtmlTextDocumentBuilder extends TextDocument { public HtmlTextDocumentBuilder(InputStream in){ //check that it is an HTML text document or throw error } public Document createDocument() { return new HtmlTextDocument(); } public void printTextHeader () { // Code for header HTML text header here. } public void printTextFooter () { // Code for header HTML text footer here. } ... }
In the above example, two types of text documents are processed, plain text Document and HTML text document. To print any of the document, the procedure to print the document body is the same. However the methods to print the header and the footer are different for both the documents. Therefore they are defined in the abstract class but the specialized implementation is provided in the subclass. printPage() is the template method. Two types of objects are used, PlainTextDocument and HtmlTextDocument. A Factory method createDocument() is called within the Template method printPage() for this purpose.
Prototype Design Pattern
The Prototype pattern creates a new object by cloning an existing object. The client using the prototype object does not need to know what kind of object it deals with as long as the concrete prototype extends or implements the prototype interface or class. The concrete prototype object is responsible for cloning itself and hence returning the cloned object. The pattern thus enables a client to create the kind of object required at runtime by selecting the appropriate prototype. The prototype classes are created generically by the client without the client knowing the exact type of the concrete prototype. New concrete prototypes can be added at run-time as long as they are similar to the abstract prototype [11]. This pattern allows you to avoid expensive initialization routines when you construct objects that are very similar. Also the goal is to minimize the amount of work needed in creating new objects when the initialization routines are expensive. For example, if the initialization routine requires database queries, file look ups, or service calls and you already have other objects in the system that are very similar to the object you are constructing, then the prototype pattern comes into picture and helps you avoid those expensive initializations.
We have a look at the UML diagram for the prototype design pattern:
From the above diagram we can decipher the following things that are: PrototypeManager class is just a manager class that is used to add and retrieve prototypes by an index number; it has the following variable and methods:
- prototypeList variable: It is the collection that stores all the prototypes
- AddPrototype method: Allows you to add a prototype to the collection and assigning it an index number
- GetPrototype method: Allows you to retrieve a prototype from the collection using an index number
The IPrototype interface specifies the methods that all prototype classes must implement. It has the Clone method that returns an IPrototype interface.
The ConcretePrototype class is the actual prototype class; it implements the IPrototype interface and has the following property and method:
- copyProperty variable holds the information that is prepopulated. If the variable value is changed then the new instances created will have the new value.
- Clone method will make a copy of itself and return it. If the copyProperty is a value type (such as int or string) then we can use shallow copy. If the copyProperty is a reference type (such as an object that contains other objects) then we go for deep copy of the variable.
The key to this pattern is that you will create your first object with the expensive initializations, and then store the values as a prototype in the repository. When you need create the same object again you can just get the copy of the prototype from the repository with all the values already populated. This reduces the performance overhead [12].
Java Sample code to show prototype design pattern
The following is an example of the Prototype Pattern. The prototype object is an Animal object. The Animal prototype contains two concrete prototype subclasses namely Sheep and Chicken. TheAnimalCreator class contains references to the two concrete prototypes. During the initialization of theAnimalCreator class the two concrete prototypes, Sheep and Chicken are created and stored as the two concrete prototypes members of the AnimalCreator class. The AnimalCreator class contains a retrieveAnimal method that clones a prototype Animal depending on the parameter that is passed to it.
Animal.java
The Animal class is the abstract prototype of the two concrete prototypes in the example. The client invokes methods on the two different concrete prototypes through the Animal type to ensure the client does not know the type of the concrete prototypes. Most importantly, the Animal prototype defines a clone method to assist the two subtypes or concrete prototypes to clone themselves.
Code:
public Animal clone() { Animal clonedAnimal = null; try { clonedAnimal = (Animal) super.clone(); clonedAnimal.setDescription(description); clonedAnimal.setNumberOfLegs(numberOfLegs); clonedAnimal.setName(name); } catch (CloneNotSupportedException e) { e.printStackTrace(); } // catch return clonedAnimal; } // method clone
Sheep.java
The Sheep object is a concrete prototype that extends the Animal prototype. The Sheep prototype has a clone method to clone itself to create a new object.
Code:
public class Sheep extends Animal {
Chicken.java
The Chicken object is a concrete prototype that extends the Animal prototype. The Chicken prototype has a clone method to clone itself to create a new object.
Code:
public class Chicken extends Animal {
AnimalCreator.java
The AnimalCreator class is used to create and manage prototype objects. The AnimalCreator class contains two concrete prototypes that are initialized during the initialization of the class. The AnimalCreator class forms part of the "Prototype" pattern by returning a cloned object (Animal) to the client without the client knowing the type of the prototype.
Code:
public Animal retrieveAnimal(String kindOfAnimal) { if ("Chicken".equals(kindOfAnimal)) { return (Animal) chicken.clone(); } else if ("Sheep".equals(kindOfAnimal)) { return (Animal) sheep.clone(); } // if return null; } // method retrieveAnimal
AnimalClient.java
The AnimalClient class makes use of the AnimalCreator class to create a concrete prototypes of typeAnimal. The AnimalClient class does not know the type of the concrete prototypes but references them through the Animal prototype.
Code:
AnimalCreator animalCreator = new AnimalCreator(); Animal[] animalFarm = new Animal[8]; animalFarm[0] = animalCreator.retrieveAnimal("Chicken"); animalFarm[1] = animalCreator.retrieveAnimal("Chicken"); animalFarm[2] = animalCreator.retrieveAnimal("Chicken"); animalFarm[3] = animalCreator.retrieveAnimal("Chicken"); animalFarm[4] = animalCreator.retrieveAnimal("Sheep"); animalFarm[5] = animalCreator.retrieveAnimal("Sheep"); animalFarm[6] = animalCreator.retrieveAnimal("Sheep"); animalFarm[7] = animalCreator.retrieveAnimal("Sheep"); for (int i= 0; i<=7; i++) { System.out.println(animalFarm[i].helloAnimal()); } // for [13]
Difference between factory method pattern and prototype pattern
The prototype pattern and the factory pattern are very similar in both intent and functionality. Both are creational patterns that will create objects of some interface without needing to specifically know the underlying class types.
The main difference between the two patterns however involves how objects are constructed. The factory pattern will, generally, construct an object using the same construction parameters each time. Each object will be initialized with the same state information and be roughly equivalent to each other. The prototype pattern, on the other hand, can use any clone able object that is given to it — even if those objects are of the same class type but with different state information assigned to them. Each object then becomes the prototype or template for any objects cloned from them. An example can demonstrate this:
public void factoryDoSomething(Factory factory) { Point pt = factory.createPoint(); ... do something with the point ... }
public void prototypeDoSomething(Point prototype) { Point pt = (Point) prototype.clone(); ... do something with the point ... }
You will notice that in the factoryDoSomething method, the point that is created is initialized in the same way and cannot be customized1. The prototypeDoSomething method can create a point from any other point with any type of state assigned to it. We could have called it with a "new Point(23,85)" or a "new Point(2929,59483)" and the cloned object would have similar state to those prototypes. The, ahem, point of the matter is that we can customize the state of the objects that will be created by the prototype pattern.
Another major difference between the two patterns is the type of classes that can be created. A factory pattern will know (either through a registry or through sub classing) the various class types that can be created. The prototype pattern is not restricted to this as long as the object can be cloned. This allows the cloning of objects that are loaded dynamically from a class loader or ddl library or some other source where the class of the object is unknown either to the application or the component itself.
Lastly, a factory pattern can handle a limited set of class types efficiently but gets bogged down as the number of types increase. The more types a factory pattern can create, the more cumbersome the factory pattern becomes from the overhead of managing those classes (both in the factory itself and in creating the necessary supporting classes). If the classes that are managed by the factory pattern are a hierarchy of classes for any given implementation, that hierarchy is generally repeated for each type regardless of how similar each class is to any other implementation. If the factory pattern uses a registry of some sort, the registry becomes harder to manage and certainly consumes more resources. On the other hand, the prototype pattern does not suffer from these issues since the pattern is focused on an existing object. The pattern is very scalable as the types increase because it has no management or overhead associated to it. If a class hierarchy is involved for each implementation, the pattern becomes very efficient because it can reduce the number of redundant classes involved since any class can be simply cloned (in other words, you can mix and match classes from different types where applicable).
To sum up, a prototype pattern provides benefits over a factory pattern when the state of the objects should can be customized by the calling application, the class types are dynamically loaded or otherwise unknown or when there is a large number of class type implementations that potentially deal with a lot of similar classes [14].
Use the Prototype pattern when
You want to:
- Hide concrete classes from the client.
- Add and remove new classes (via prototypes) at runtime.
- Keep the number of classes in the system to a minimum.
- Adapt to changing structures of data at runtime.
Consider using this pattern:
- With the Composite pattern, to provide archiving.
- Instead of the Factory Method pattern, when subclasses start proliferating.
Use the Factory Method pattern when
- Flexibility is important.
- Objects can be extended in subclasses
- There is a specific reason why one subclass would be chosen over another-this logic forms part of the Factory Method.
- A client delegates responsibilities to subclasses in parallel hierarchies.
Consider using this pattern instead of:
- The Abstract Factory, Prototype, or Builder patterns, which are more flexible (though also more complex).The Prototype pattern to store a set of objects to clone from the abstract factory [15].
References
<references />