CSC/ECE 517 Fall 2012/ch2b 2w37 ms: Difference between revisions
No edit summary |
No edit summary |
||
(69 intermediate revisions by 2 users not shown) | |||
Line 1: | Line 1: | ||
<big>''' Adapter pattern and the related patterns (Bridge, Decorator, Facade)'''</big><br> | <big>''' Adapter pattern and the related patterns (Bridge, Decorator, Facade)'''</big><br> | ||
The adapter design pattern allows the user to make changes to the existing class with other class libraries without changing the code for the existing class. The Bridge, Decorator and the Facade pattern look somewhat similar to the adapter pattern but their intent is different and that intent is what separates the above patterns from each other. | The adapter design pattern allows the user to make changes to the existing class with other class libraries without changing the code for the existing class. <ref name="Gof">http://c2.com/cgi/wiki?GangOfFour</ref> The Bridge, Decorator and the Facade pattern look somewhat similar to the adapter pattern but their intent is different and that intent is what separates the above patterns from each other. | ||
=== Adapter Pattern === | === Adapter Pattern === | ||
Adapter pattern plays an important role when you want to incompatible interfaces to work together.The real world example for an adapter pattern is the travel power adapter.Different countries have different socket and plug configuration. So you can use an adapter to fit a plug into a socket that initially was not possible due to different interface designs. | Adapter pattern plays an important role when you want to incompatible interfaces to work together. It is generally used for third party code or code that we cannot modify. If such code uses an interface which is different from the interface we wish to use, adapter is the answer to the problem.The real world example for an adapter pattern is the travel power adapter.Different countries have different socket and plug configuration. So you can use an adapter to fit a plug into a socket that initially was not possible due to different interface designs. <ref name="adapter">http://javapapers.com/design-patterns/adapter-pattern/</ref> | ||
==== Implementattion ==== | ==== Implementattion ==== | ||
Line 11: | Line 11: | ||
===== Adapter implementation using inheritance ===== | ===== Adapter implementation using inheritance ===== | ||
This method can be used when you have incompatible method that needs to be used in other class. Using inheritance a "is-a" relationship is established between the base class and super class. The new compatible methods will be contained in the inherited adapter class. | This method can be used when you have incompatible method that needs to be used in other class. Using inheritance a [http://en.wikipedia.org/wiki/Is-a "is-a"] relationship is established between the base class and super class. The new compatible methods will be contained in the inherited adapter class. <ref name="adapter">http://javapapers.com/design-patterns/adapter-pattern/</ref> | ||
public class CylindricalSocket { | public class CylindricalSocket { | ||
Line 38: | Line 38: | ||
} | } | ||
===== Adapter implementation using composition ===== | ===== Adapter implementation using composition ===== | ||
The other approach is to have a base class as an attribute in the adapter class. This creates an [http://en.wikipedia.org/wiki/Has-a "has-a"]relationship between the base class and the sub class. <ref name="adapter">http://javapapers.com/design-patterns/adapter-pattern/</ref> | |||
public class CylindricalSocket { | public class CylindricalSocket { | ||
Line 72: | Line 73: | ||
===== Composition or inheritance to implement Adapter Pattern? ===== | ===== Composition or inheritance to implement Adapter Pattern? ===== | ||
* Composition is preferred over inheritance since using composition it is easy to change the behavior of a class. | * Composition is preferred over inheritance since using composition it is easy to change the behavior of a class. <ref name="adapter">http://javapapers.com/design-patterns/adapter-pattern/</ref> | ||
==== Adapter pattern in Java Library==== | |||
* [http://docs.oracle.com/javase/6/docs/api/java/io/InputStreamReader.html java.io.InputStreamReader(InputStream)] | |||
* [http://docs.oracle.com/javase/1.4.2/docs/api/java/io/OutputStreamWriter.html java.io.OutputStreamWriter(OutputStream)] <ref name="adapter">http://javapapers.com/design-patterns/adapter-pattern/</ref> | |||
=== Bridge Pattern === | === Bridge Pattern === | ||
As stated by GoF a bridge design patterns intent is to “Decouple an abstraction from its implementation so that the two can vary independently”. | As stated by GoF a bridge design patterns intent is to “Decouple an abstraction from its implementation so that the two can vary independently”. <ref name="bridge">http://javapapers.com/design-patterns/bridge-design-pattern/</ref> | ||
===== Elements of Bridge Design Pattern ===== | ===== Elements of Bridge Design Pattern ===== | ||
* Abstraction: This is where the abstraction interface is defined. | *''' Abstraction:''' This is where the abstraction interface is defined. | ||
For example: A Vehicle class which has a manufacture method. | |||
* Refined Abstraction: Refined Abstraction extends the interface defined by Abstraction. | * '''Refined Abstraction:''' Refined Abstraction extends the interface defined by Abstraction. | ||
For example, a Car class or a Bike class which has a manufacture method which is more refined than the Vehicle class. | For example, a Car class or a Bike class which has a manufacture method which is more refined than the Vehicle class. | ||
* Implementor: It defines the interface for the implementation classes. It defines the basic operation. | * '''Implementor:''' It defines the interface for the implementation classes. It defines the basic operation. | ||
For example, the Workshop class acts as an implementor with the work() method. | For example, the Workshop class acts as an implementor with the work() method. | ||
* Concrete Implementation: This implements the Implementor interface and gives it a more concrete implementation. | * '''Concrete Implementation:''' This implements the Implementor interface and gives it a more concrete implementation. | ||
For example the Produce and the Assemble class with the work() method provides the concrete implementation. | For example the Produce and the Assemble class with the work() method provides the concrete implementation. <ref name="Gof">http://c2.com/cgi/wiki?GangOfFour</ref><ref name="bridge">http://javapapers.com/design-patterns/bridge-design-pattern/</ref> | ||
[[File:Bridge-Pattern.jpg|300 px|thumb|right|UML Diagram for Bridge-Pattern <ref name="bridge">http://javapapers.com/design-patterns/bridge-design-pattern/</ref>]] | |||
[[File:WBP.jpg|350 px|thumb|left|Without Bridge-Pattern <ref name="bridge">http://javapapers.com/design-patterns/bridge-design-pattern/</ref>]][[File:bp.jpg|300 px|thumb|center|With Bridge-Pattern <ref name="bridge">http://javapapers.com/design-patterns/bridge-design-pattern/</ref>]] | |||
<br> | |||
<br> | |||
<br> | |||
<br> | |||
<br> | |||
<br> | |||
<br> | |||
<br> | |||
===== Example code for Bridge pattern ===== | |||
'''Vehicle Interface''' <ref name="bridge">http://javapapers.com/design-patterns/bridge-design-pattern/</ref> | |||
// abstraction in bridge pattern | |||
abstract class Vehicle { | |||
protected Workshop workShop1; | |||
protected Workshop workShop2; | |||
protected Vehicle(Workshop workShop1, Workshop workShop2) { | |||
this.workShop1 = workShop1; | |||
this.workShop2 = workShop2; | |||
} | |||
abstract public void manufacture(); | |||
} | |||
'''Car class''' <ref name="bridge">http://javapapers.com/design-patterns/bridge-design-pattern/</ref> | |||
//Refine abstraction 1 in bridge pattern | |||
public class Car extends Vehicle { | |||
public Car(Workshop workShop1, Workshop workShop2) { | |||
super(workShop1, workShop2); | |||
} | |||
@Override | |||
public void manufacture() { | |||
System.out.print("Car "); | |||
workShop1.work(); | |||
workShop2.work(); | |||
} | |||
} | |||
'''Bike Class''' <ref name="bridge">http://javapapers.com/design-patterns/bridge-design-pattern/</ref> | |||
== | // Refine abstraction 2 in bridge pattern | ||
public class Bike extends Vehicle { | |||
public Bike(Workshop workShop1, Workshop workShop2) { | |||
super(workShop1, workShop2); | |||
} | |||
@Override | |||
public void manufacture() { | |||
System.out.print("Bike "); | |||
workShop1.work(); | |||
workShop2.work(); | |||
} | |||
} | |||
'''Workshop Interface''' <ref name="bridge">http://javapapers.com/design-patterns/bridge-design-pattern/</ref> | |||
// Implementor for bridge pattern | |||
public interface Workshop { | |||
abstract public void work(); | |||
} | |||
'''Produce Class''' <ref name="bridge">http://javapapers.com/design-patterns/bridge-design-pattern/</ref> | |||
// Concrete implementation 1 for bridge pattern | |||
public class Produce implements Workshop { | |||
@Override | |||
public void work() { | |||
System.out.print("Produced"); | |||
} | |||
} | |||
'''Assemble Class''' <ref name="bridge">http://javapapers.com/design-patterns/bridge-design-pattern/</ref> | |||
//Concrete implementation 2 for bridge pattern | |||
public class Assemble implements Workshop { | |||
@Override | |||
public void work() { | |||
System.out.println(" Assembled."); | |||
} | |||
} | |||
'''Demonstration of bridge design '''<ref name="bridge">http://javapapers.com/design-patterns/bridge-design-pattern/</ref> | |||
public class BridgePattern { | |||
public static void main(String[] args) { | |||
Vehicle vehicle1 = new Car(new Produce(), new Assemble()); | |||
vehicle1.manufacture(); | |||
Vehicle vehicle2 = new Bike(new Produce(), new Assemble()); | |||
vehicle2.manufacture(); | |||
} | |||
} | |||
'''Output:''' | |||
Car Produced Assembled. | |||
Bike Produced Assembled. | |||
===== Bridge vs Adapter pattern ===== | ===== Bridge vs Adapter pattern ===== | ||
* Two incompatable classes can be made to work together using adapter pattern. | * Two incompatable classes can be made to work together using adapter pattern. | ||
* Bridge pattern creates two separate hierarchies by separating the abstraction from the implementation. | * Bridge pattern creates two separate hierarchies by separating the abstraction from the implementation. <ref name="bridge">http://javapapers.com/design-patterns/bridge-design-pattern/</ref> | ||
While the two patterns may seem similar according to the GoF- "Adapter makes things work after they're designed; Bridge makes them work before they are. [GoF, p219]".<ref name="Gof">http://c2.com/cgi/wiki?GangOfFour</ref> | |||
The adapter pattern is useful when we have code that is either third party or maybe in house, over which we do not have any control and such code do not fit with the interface that we wish to use. In such a case we use either of two (delegation or inheritance) model of the adapter pattern to change the existing classes (which do not fit our interface) and cast them to our desired interface. | |||
The bridge pattern on the other hand is something we implement upfront on classes that have orthogonal hierarchies. It provides a way to decouple the interface and the implementation in such a way that you don't get an insane number of classes. In bridge pattern we usually deal with classes that vary in their implementations a lot and we want to incorporate the functionality of the implementation classes as much as possible. Bridge pattern is many times implemented with the help adapter pattern to give the orthogonal hierarchies a common interface. | |||
For example,we have a [http://docs.oracle.com/javase/1.4.2/docs/api/java/io/FileReader.html FileReader interface] with two implementations. One that reads file from windows system and one that read Files from Linux systems. Now there are two more interface say [http://en.wikipedia.org/wiki/Memory-mapped_file MemoryMappedFiles] and [http://file.downloadatoz.com/rad-file-extension/ RADFiles]. Now bridge pattern will help you in not having to write four classes MemoryMappedWindowsFileReader, MemoryMappedLinuxFileReader, RADWindowsFileReader, RADWindowsFileReader. | |||
Use adapter pattern to adapt MemoryMappedFiles and RADFiles to a common interface (assuming both implementations have SpecialFile interface in common). Also WindowsFileReader and LinuxFileReader are two implementations of the FileReader interface. | |||
public interface CrossPlatformSpecialPurposeFileReader{ | |||
public void readFile(); // used for adapting | |||
} | |||
SpecialWindowsFileReader extends WindowsFileReader implements CrossPlatformSpecialPurposeFileReader{ | |||
SpecialFile specialFile; | |||
public SpecialWindowsFileReader(SpecialFile specialFile){ | |||
this.specialFile = specialFile; | |||
} | |||
public void readFile(){ | |||
byte fileBytes[] = this.read(); // read platform specific and convert to bytes | |||
this.specialFile(fileBytes) // decouples from the filesystem specifics. | |||
} | |||
} | |||
SpecialLinuxFileReader extends LinuxFileReader implements CrossPlatformSpecialPurposeFileReader{ | |||
SpecialFile specialFile; | |||
public SpecialLinuxFileReader(SpecialFile specialFile){ | |||
this.specialFile = specialFile; | |||
} | |||
public void readFile(){ | |||
byte fileBytes[] = this.read(); // read platform specific and convert to bytes | |||
this.specialFile(fileBytes) // decouples from the filesystem specifics. | |||
} | |||
} | |||
'''Bridge Pattern''' | |||
public class Bridge{ | |||
public static void main(String args[]){ | |||
CrossPlatformSpecialPurposeFileReader specialFiles[] = new CrossPlatformSpecialPurposeFileReader[2]; | |||
specialFiles[0] = new SpecialWindowsFileReader(new MemoryMappedFiles()); | |||
specialFiles[1] = new SpecialLinuxFileReader(new RADFiles()); | |||
// deouples two orthogonal implementations under one interface. | |||
for(CrossPlatformSpecialPurposeFileReader reader : specialFiles){ | |||
reader.readFile(); | |||
} | |||
} | |||
} | |||
=== Decorator Pattern === | === Decorator Pattern === | ||
The decorator pattern adds responsibility to an object dynamically. The decorator design pattern is used to extend the behavior of an object dynamically. In order to extend the behavior we have to construct an wrapper around the object. Inheritance is not feasible since it is applied to an entire class. With the decorator pattern it is possible to select any particular instance and modify its behavior leaving the other instances unmodified.<ref name="Gof">http://c2.com/cgi/wiki?GangOfFour</ref><ref name="decorator">http://javapapers.com/design-patterns/decorator-pattern/</ref> | |||
[[File:Decorator-Pattern.jpg|200 px|thumb|right|UML Diagram for Decorator-Pattern <ref name="decorator">http://javapapers.com/design-patterns/decorator-pattern/</ref> ]] | |||
==== Implementation of Decorator Pattern ==== | |||
First start with the interface which will be used by the class having the decoration design. | |||
The example below explains how you first create a base ice cream and then decorate that ice cream by adding new toppings. The added topping changes the behavior of that ice cream. i.e. it gives the ice cream more taste. | |||
The interface below contains an makeIcecream() method which has not been implemented yet.<ref name="decorator">http://javapapers.com/design-patterns/decorator-pattern/</ref> | |||
public interface Icecream { | |||
public String makeIcecream(); | |||
} | |||
The SimpleIceCream Class provides an implementation to the makeIcecream() method. This is the class which acts as a base class on which decorations will be added.<ref name="decorator">http://javapapers.com/design-patterns/decorator-pattern/</ref> | |||
public class SimpleIcecream implements Icecream { | |||
@Override | |||
public String makeIcecream() { | |||
return "Base Icecream"; | |||
} | |||
} | |||
The class below is the crux of the design pattern. Here is where all the Decoration is actually provided to an instance of the object.It contains an attribute of type Icecream. Once the instance is assigned using the constructor the instance method will be invoked. <ref name="decorator">http://javapapers.com/design-patterns/decorator-pattern/</ref> | |||
abstract class IcecreamDecorator implements Icecream { | |||
protected Icecream specialIcecream; | |||
public IcecreamDecorator(Icecream specialIcecream) { | |||
this.specialIcecream = specialIcecream; | |||
} | |||
public String makeIcecream() { | |||
return specialIcecream.makeIcecream(); | |||
} | |||
} | |||
The NuttyDecorator and HoneyDecorator are the two concrete classes that implement the abstract decorator class IcecreamDecorator. <ref name="decorator">http://javapapers.com/design-patterns/decorator-pattern/</ref> | |||
public class NuttyDecorator extends IcecreamDecorator { | |||
public NuttyDecorator(Icecream specialIcecream) { | |||
super(specialIcecream); | |||
} | |||
public String makeIcecream() { | |||
return specialIcecream.makeIcecream() + addNuts(); | |||
} | |||
private String addNuts() { | |||
return " + cruncy nuts"; | |||
} | |||
} | |||
public class HoneyDecorator extends IcecreamDecorator { | |||
public HoneyDecorator(Icecream specialIcecream) { | |||
super(specialIcecream); | |||
} | |||
public String makeIcecream() { | |||
return specialIcecream.makeIcecream() + addHoney(); | |||
} | |||
private String addHoney() { | |||
return " + sweet honey"; | |||
} | |||
} | |||
===== Decorator pattern in Java Library===== | |||
* [http://docs.oracle.com/javase/6/docs/api/java/io/BufferedReader.html java.io.BufferedReader] | |||
* [http://docs.oracle.com/javase/1.4.2/docs/api/java/io/FileReader.html java.io.FileReader] | |||
* [http://docs.oracle.com/javase/6/docs/api/java/io/Reader.html java.io.Reader] <ref name="decorator">http://javapapers.com/design-patterns/decorator-pattern/</ref> | |||
==== Adaptor Pattern vs Decorator Pattern==== | |||
* Adapter provides a different interface to its subject. | |||
* Decorator provides an enhanced interface. <ref name="decorator">http://javapapers.com/design-patterns/decorator-pattern/</ref> | |||
*In adapter pattern we adapt an existing interface to an interface that suits our needs. On the other hand in decorator pattern the aim is to enhance the existing interface such that the new interface can replace the existing interface without any changes in code. <ref >http://sourcemaking.com/design_patterns/decorator</ref> | |||
=== Facade Pattern === | === Facade Pattern === | ||
[[File:Wof.jpg|200 px|thumb|right|Without Facade-Pattern <ref name="facade">http://javapapers.com/design-patterns/facade-design-pattern/</ref>]] | |||
[[File:Wf.jpg|200 px|thumb|right|With Facade-Pattern <ref name="facade">http://javapapers.com/design-patterns/facade-design-pattern/</ref>]] | |||
GoF defines a facade design pattern as a pattern which , “Provides a unified interface to a set of interfaces in a subsystem. Facade Pattern defines a higher-level interface that makes the subsystem easier to use.” <ref name="Gof">http://c2.com/cgi/wiki?GangOfFour</ref><ref name="facade">http://javapapers.com/design-patterns/facade-design-pattern/</ref> | |||
Consider a software component. In order to get the job done this component might have to expose a of interfaces so that it can interact with other components in a process flow. Facade pattern simplifies this process by providing an unified interface. It builds an additional layer of abstraction over the existing abstract layer to simplify the process. | |||
A microwave oven is made up of components like trasnformer, capacitor, magnetron, waveguide and some small other components. For a microwave to work all these different components needs to be executed in a sequence. If all these components had separate interfaces it would have been hard and complicated.Hence oven provides you buttons which can be considered as a facade. When you click on single button the job is done. That single button works as an abstraction layer between the user and the internal components. <ref name="facade">http://javapapers.com/design-patterns/facade-design-pattern/</ref> | |||
==== Facade Pattern in java library ==== | |||
[http://docs.oracle.com/javaee/6/api/javax/faces/context/ExternalContext.html ExternalContext Class] in java performs cookie management by using an facade pattern. It makes use of components such as [http://docs.oracle.com/javaee/5/api/javax/servlet/http/HttpSession.html HttpSession],[http://docs.oracle.com/javaee/6/api/javax/servlet/ServletContext.html ServletContext], [http://docs.oracle.com/javaee/5/api/javax/servlet javax.servlet.http.HttpServletRequest] and [http://docs.oracle.com/javaee/5/api/javax/servlet/http/HttpServletResponse.html javax.servlet.http.HttpServletResponse]. <ref name="facade">http://javapapers.com/design-patterns/facade-design-pattern/</ref> | |||
==== Facade Pattern vs Adapter Pattern ==== | |||
* Adapter pattern is to make an incompatible class work with other class where as facade provides programming comfort by providing an unified interface. | |||
* Adapter Pattern using inheritance increases inter dependencies whereas facade pattern provides loose coupling | |||
* Changing data to suit the interface of a subsystem is done by facade whereas changing the structure of a system is done by adapter pattern | |||
* Facade increases subsystem independence and portability. This is not possible using the adapter pattern. <ref name="facade">http://javapapers.com/design-patterns/facade-design-pattern/</ref> | |||
* In an adapter there is an interface we design to which is not the case in facade. Adapter and Facade are both wrappers; but they are different kinds of wrappers. The intent of Facade is to produce a simpler interface, and the intent of Adapter is to design to an existing interface. | |||
* In an adapter an object might need to behave in a polymorphic manner which is not the case in a facade pattern. | |||
* In an facade a simpler interface is needed which is not the case necessarily in an adapter pattern | |||
* While Facade routinely wraps multiple objects and Adapter wraps a single object; Facade could front-end a single complex object and Adapter could wrap several legacy objects | |||
=== Conclusion === | |||
* One interface is converted into another using an adapter interface. On the other hand, decorator pattern adds responsibility instead of altering an interface. Using decorator recursive composition is possible which is not the case using adapter pattern. | |||
* With the help of the bridge pattern, the abstraction and the implementation varies independently while the adapter pattern makes incompatible classes to work together. | |||
* Adapter redefines an old interface whereas facade defines a new interface.<ref> http://snehaprashant.blogspot.com/2008/08/adapter-pattern.html</ref> | |||
==References== | |||
<references /> |
Latest revision as of 18:21, 19 November 2012
Adapter pattern and the related patterns (Bridge, Decorator, Facade)
The adapter design pattern allows the user to make changes to the existing class with other class libraries without changing the code for the existing class. <ref name="Gof">http://c2.com/cgi/wiki?GangOfFour</ref> The Bridge, Decorator and the Facade pattern look somewhat similar to the adapter pattern but their intent is different and that intent is what separates the above patterns from each other.
Adapter Pattern
Adapter pattern plays an important role when you want to incompatible interfaces to work together. It is generally used for third party code or code that we cannot modify. If such code uses an interface which is different from the interface we wish to use, adapter is the answer to the problem.The real world example for an adapter pattern is the travel power adapter.Different countries have different socket and plug configuration. So you can use an adapter to fit a plug into a socket that initially was not possible due to different interface designs. <ref name="adapter">http://javapapers.com/design-patterns/adapter-pattern/</ref>
Implementattion
Adapter implementation using inheritance
This method can be used when you have incompatible method that needs to be used in other class. Using inheritance a "is-a" relationship is established between the base class and super class. The new compatible methods will be contained in the inherited adapter class. <ref name="adapter">http://javapapers.com/design-patterns/adapter-pattern/</ref>
public class CylindricalSocket { public String supply(String cylinStem1, String cylinStem1) { System.out.println("Power power power..."); } } public class RectangularAdapter extends CylindricalSocket { public String adapt(String rectaStem1, Sting rectaStem2) { //some conversion logic String cylinStem1 = rectaStem1; String cylinStem2 = rectaStem2; return supply(cylinStem1, cylinStem2); } } public class RectangularPlug { private String rectaStem1; private String rectaStem2; public getPower() { RectangulrAdapter adapter = new RectangulrAdapter(); String power = adapter.adapt(rectaStem1, rectaStem2); System.out.println(power); } }
Adapter implementation using composition
The other approach is to have a base class as an attribute in the adapter class. This creates an "has-a"relationship between the base class and the sub class. <ref name="adapter">http://javapapers.com/design-patterns/adapter-pattern/</ref>
public class CylindricalSocket { public String supply(String cylinStem1, String cylinStem1) { System.out.println("Power power power..."); } } public class RectangularAdapter { private CylindricalSocket socket; public String adapt(String rectaStem1, Sting rectaStem2) { //some conversion logic socket = new CylindricalSocket(); String cylinStem1 = rectaStem1; String cylinStem2 = rectaStem2; return socket.supply(cylinStem1, cylinStem2); } } public class RectangularPlug { private String rectaStem1; private String rectaStem2; public getPower() { RectangulrAdapter adapter = new RectangulrAdapter(); String power = adapter.adapt(rectaStem1, rectaStem2); System.out.println(power); } }
Composition or inheritance to implement Adapter Pattern?
- Composition is preferred over inheritance since using composition it is easy to change the behavior of a class. <ref name="adapter">http://javapapers.com/design-patterns/adapter-pattern/</ref>
Adapter pattern in Java Library
- java.io.InputStreamReader(InputStream)
- java.io.OutputStreamWriter(OutputStream) <ref name="adapter">http://javapapers.com/design-patterns/adapter-pattern/</ref>
Bridge Pattern
As stated by GoF a bridge design patterns intent is to “Decouple an abstraction from its implementation so that the two can vary independently”. <ref name="bridge">http://javapapers.com/design-patterns/bridge-design-pattern/</ref>
Elements of Bridge Design Pattern
- Abstraction: This is where the abstraction interface is defined.
For example: A Vehicle class which has a manufacture method.
- Refined Abstraction: Refined Abstraction extends the interface defined by Abstraction.
For example, a Car class or a Bike class which has a manufacture method which is more refined than the Vehicle class.
- Implementor: It defines the interface for the implementation classes. It defines the basic operation.
For example, the Workshop class acts as an implementor with the work() method.
- Concrete Implementation: This implements the Implementor interface and gives it a more concrete implementation.
For example the Produce and the Assemble class with the work() method provides the concrete implementation. <ref name="Gof">http://c2.com/cgi/wiki?GangOfFour</ref><ref name="bridge">http://javapapers.com/design-patterns/bridge-design-pattern/</ref>
Example code for Bridge pattern
Vehicle Interface <ref name="bridge">http://javapapers.com/design-patterns/bridge-design-pattern/</ref>
// abstraction in bridge pattern abstract class Vehicle { protected Workshop workShop1; protected Workshop workShop2; protected Vehicle(Workshop workShop1, Workshop workShop2) { this.workShop1 = workShop1; this.workShop2 = workShop2; } abstract public void manufacture(); }
Car class <ref name="bridge">http://javapapers.com/design-patterns/bridge-design-pattern/</ref>
//Refine abstraction 1 in bridge pattern public class Car extends Vehicle { public Car(Workshop workShop1, Workshop workShop2) { super(workShop1, workShop2); } @Override public void manufacture() { System.out.print("Car "); workShop1.work(); workShop2.work(); } }
Bike Class <ref name="bridge">http://javapapers.com/design-patterns/bridge-design-pattern/</ref>
// Refine abstraction 2 in bridge pattern public class Bike extends Vehicle { public Bike(Workshop workShop1, Workshop workShop2) { super(workShop1, workShop2); } @Override public void manufacture() { System.out.print("Bike "); workShop1.work(); workShop2.work(); } }
Workshop Interface <ref name="bridge">http://javapapers.com/design-patterns/bridge-design-pattern/</ref>
// Implementor for bridge pattern public interface Workshop { abstract public void work(); }
Produce Class <ref name="bridge">http://javapapers.com/design-patterns/bridge-design-pattern/</ref>
// Concrete implementation 1 for bridge pattern public class Produce implements Workshop { @Override public void work() { System.out.print("Produced"); } }
Assemble Class <ref name="bridge">http://javapapers.com/design-patterns/bridge-design-pattern/</ref>
//Concrete implementation 2 for bridge pattern public class Assemble implements Workshop { @Override public void work() { System.out.println(" Assembled."); } }
Demonstration of bridge design <ref name="bridge">http://javapapers.com/design-patterns/bridge-design-pattern/</ref>
public class BridgePattern { public static void main(String[] args) { Vehicle vehicle1 = new Car(new Produce(), new Assemble()); vehicle1.manufacture(); Vehicle vehicle2 = new Bike(new Produce(), new Assemble()); vehicle2.manufacture(); } }
Output:
Car Produced Assembled. Bike Produced Assembled.
Bridge vs Adapter pattern
- Two incompatable classes can be made to work together using adapter pattern.
- Bridge pattern creates two separate hierarchies by separating the abstraction from the implementation. <ref name="bridge">http://javapapers.com/design-patterns/bridge-design-pattern/</ref>
While the two patterns may seem similar according to the GoF- "Adapter makes things work after they're designed; Bridge makes them work before they are. [GoF, p219]".<ref name="Gof">http://c2.com/cgi/wiki?GangOfFour</ref>
The adapter pattern is useful when we have code that is either third party or maybe in house, over which we do not have any control and such code do not fit with the interface that we wish to use. In such a case we use either of two (delegation or inheritance) model of the adapter pattern to change the existing classes (which do not fit our interface) and cast them to our desired interface.
The bridge pattern on the other hand is something we implement upfront on classes that have orthogonal hierarchies. It provides a way to decouple the interface and the implementation in such a way that you don't get an insane number of classes. In bridge pattern we usually deal with classes that vary in their implementations a lot and we want to incorporate the functionality of the implementation classes as much as possible. Bridge pattern is many times implemented with the help adapter pattern to give the orthogonal hierarchies a common interface.
For example,we have a FileReader interface with two implementations. One that reads file from windows system and one that read Files from Linux systems. Now there are two more interface say MemoryMappedFiles and RADFiles. Now bridge pattern will help you in not having to write four classes MemoryMappedWindowsFileReader, MemoryMappedLinuxFileReader, RADWindowsFileReader, RADWindowsFileReader.
Use adapter pattern to adapt MemoryMappedFiles and RADFiles to a common interface (assuming both implementations have SpecialFile interface in common). Also WindowsFileReader and LinuxFileReader are two implementations of the FileReader interface.
public interface CrossPlatformSpecialPurposeFileReader{ public void readFile(); // used for adapting } SpecialWindowsFileReader extends WindowsFileReader implements CrossPlatformSpecialPurposeFileReader{ SpecialFile specialFile; public SpecialWindowsFileReader(SpecialFile specialFile){ this.specialFile = specialFile; } public void readFile(){ byte fileBytes[] = this.read(); // read platform specific and convert to bytes this.specialFile(fileBytes) // decouples from the filesystem specifics. } } SpecialLinuxFileReader extends LinuxFileReader implements CrossPlatformSpecialPurposeFileReader{ SpecialFile specialFile; public SpecialLinuxFileReader(SpecialFile specialFile){ this.specialFile = specialFile; } public void readFile(){ byte fileBytes[] = this.read(); // read platform specific and convert to bytes this.specialFile(fileBytes) // decouples from the filesystem specifics. } }
Bridge Pattern
public class Bridge{ public static void main(String args[]){ CrossPlatformSpecialPurposeFileReader specialFiles[] = new CrossPlatformSpecialPurposeFileReader[2]; specialFiles[0] = new SpecialWindowsFileReader(new MemoryMappedFiles()); specialFiles[1] = new SpecialLinuxFileReader(new RADFiles()); // deouples two orthogonal implementations under one interface. for(CrossPlatformSpecialPurposeFileReader reader : specialFiles){ reader.readFile(); } } }
Decorator Pattern
The decorator pattern adds responsibility to an object dynamically. The decorator design pattern is used to extend the behavior of an object dynamically. In order to extend the behavior we have to construct an wrapper around the object. Inheritance is not feasible since it is applied to an entire class. With the decorator pattern it is possible to select any particular instance and modify its behavior leaving the other instances unmodified.<ref name="Gof">http://c2.com/cgi/wiki?GangOfFour</ref><ref name="decorator">http://javapapers.com/design-patterns/decorator-pattern/</ref>
Implementation of Decorator Pattern
First start with the interface which will be used by the class having the decoration design. The example below explains how you first create a base ice cream and then decorate that ice cream by adding new toppings. The added topping changes the behavior of that ice cream. i.e. it gives the ice cream more taste.
The interface below contains an makeIcecream() method which has not been implemented yet.<ref name="decorator">http://javapapers.com/design-patterns/decorator-pattern/</ref>
public interface Icecream { public String makeIcecream(); }
The SimpleIceCream Class provides an implementation to the makeIcecream() method. This is the class which acts as a base class on which decorations will be added.<ref name="decorator">http://javapapers.com/design-patterns/decorator-pattern/</ref>
public class SimpleIcecream implements Icecream { @Override public String makeIcecream() { return "Base Icecream"; } }
The class below is the crux of the design pattern. Here is where all the Decoration is actually provided to an instance of the object.It contains an attribute of type Icecream. Once the instance is assigned using the constructor the instance method will be invoked. <ref name="decorator">http://javapapers.com/design-patterns/decorator-pattern/</ref>
abstract class IcecreamDecorator implements Icecream { protected Icecream specialIcecream; public IcecreamDecorator(Icecream specialIcecream) { this.specialIcecream = specialIcecream; } public String makeIcecream() { return specialIcecream.makeIcecream(); } }
The NuttyDecorator and HoneyDecorator are the two concrete classes that implement the abstract decorator class IcecreamDecorator. <ref name="decorator">http://javapapers.com/design-patterns/decorator-pattern/</ref>
public class NuttyDecorator extends IcecreamDecorator { public NuttyDecorator(Icecream specialIcecream) { super(specialIcecream); } public String makeIcecream() { return specialIcecream.makeIcecream() + addNuts(); } private String addNuts() { return " + cruncy nuts"; } }
public class HoneyDecorator extends IcecreamDecorator { public HoneyDecorator(Icecream specialIcecream) { super(specialIcecream); } public String makeIcecream() { return specialIcecream.makeIcecream() + addHoney(); } private String addHoney() { return " + sweet honey"; } }
Decorator pattern in Java Library
- java.io.BufferedReader
- java.io.FileReader
- java.io.Reader <ref name="decorator">http://javapapers.com/design-patterns/decorator-pattern/</ref>
Adaptor Pattern vs Decorator Pattern
- Adapter provides a different interface to its subject.
- Decorator provides an enhanced interface. <ref name="decorator">http://javapapers.com/design-patterns/decorator-pattern/</ref>
- In adapter pattern we adapt an existing interface to an interface that suits our needs. On the other hand in decorator pattern the aim is to enhance the existing interface such that the new interface can replace the existing interface without any changes in code. <ref >http://sourcemaking.com/design_patterns/decorator</ref>
Facade Pattern
GoF defines a facade design pattern as a pattern which , “Provides a unified interface to a set of interfaces in a subsystem. Facade Pattern defines a higher-level interface that makes the subsystem easier to use.” <ref name="Gof">http://c2.com/cgi/wiki?GangOfFour</ref><ref name="facade">http://javapapers.com/design-patterns/facade-design-pattern/</ref>
Consider a software component. In order to get the job done this component might have to expose a of interfaces so that it can interact with other components in a process flow. Facade pattern simplifies this process by providing an unified interface. It builds an additional layer of abstraction over the existing abstract layer to simplify the process.
A microwave oven is made up of components like trasnformer, capacitor, magnetron, waveguide and some small other components. For a microwave to work all these different components needs to be executed in a sequence. If all these components had separate interfaces it would have been hard and complicated.Hence oven provides you buttons which can be considered as a facade. When you click on single button the job is done. That single button works as an abstraction layer between the user and the internal components. <ref name="facade">http://javapapers.com/design-patterns/facade-design-pattern/</ref>
Facade Pattern in java library
ExternalContext Class in java performs cookie management by using an facade pattern. It makes use of components such as HttpSession,ServletContext, javax.servlet.http.HttpServletRequest and javax.servlet.http.HttpServletResponse. <ref name="facade">http://javapapers.com/design-patterns/facade-design-pattern/</ref>
Facade Pattern vs Adapter Pattern
- Adapter pattern is to make an incompatible class work with other class where as facade provides programming comfort by providing an unified interface.
- Adapter Pattern using inheritance increases inter dependencies whereas facade pattern provides loose coupling
- Changing data to suit the interface of a subsystem is done by facade whereas changing the structure of a system is done by adapter pattern
- Facade increases subsystem independence and portability. This is not possible using the adapter pattern. <ref name="facade">http://javapapers.com/design-patterns/facade-design-pattern/</ref>
- In an adapter there is an interface we design to which is not the case in facade. Adapter and Facade are both wrappers; but they are different kinds of wrappers. The intent of Facade is to produce a simpler interface, and the intent of Adapter is to design to an existing interface.
- In an adapter an object might need to behave in a polymorphic manner which is not the case in a facade pattern.
- In an facade a simpler interface is needed which is not the case necessarily in an adapter pattern
- While Facade routinely wraps multiple objects and Adapter wraps a single object; Facade could front-end a single complex object and Adapter could wrap several legacy objects
Conclusion
- One interface is converted into another using an adapter interface. On the other hand, decorator pattern adds responsibility instead of altering an interface. Using decorator recursive composition is possible which is not the case using adapter pattern.
- With the help of the bridge pattern, the abstraction and the implementation varies independently while the adapter pattern makes incompatible classes to work together.
- Adapter redefines an old interface whereas facade defines a new interface.<ref> http://snehaprashant.blogspot.com/2008/08/adapter-pattern.html</ref>
References
<references />