Friday, February 28, 2014

Structural Design Pattern : Bridge Design Pattern



Bridge Design Pattern is used where we need to decouple an abstraction from its implementation so that the two can vary independently

This DP decouples implementation class and abstract class by providing a bridge structure between them.

It involves an interface which acts as a bridge which makes the functionality of concrete classes independent from interface implementer classes. Both types of classes can be altered structurally without affecting each other.

Simple example 

1)    If we have a USB cable (bridge), then we can connect any printer to any computer to start printing. It really doesn't matter if it's a laser printer or a color printer, either Windows PC or Mac. Because we know all the printers will allow the computers to print, makes sense?
2)    In particular this pattern is useful in graphic toolkits that need to run on multiple platforms. You'll  see this in AWT, where a component has a component peer which does the OS specific operations. Also the Collections framework has examples of the bridge interface: ArrayList and LinkedList are implementing List. And List provides common methods to add, remove or check size. 

The Bridge pattern should be used when both the class as well as what it does vary often. The bridge pattern can also be thought of as two layers of abstraction. When the abstractions and implementations should not be bound at compile time, and should be independently extensible the pattern should be used. 

The bridge pattern applies when there is a need to avoid permanent binding between an abstraction and an implementation and when the abstraction and implementation need to vary independently. Using the bridge pattern would leave the client code unchanged with no need to recompile the code.

Sometimes an abstraction should have different implementations; consider an object that handles persistence of objects over different platforms using either relational databases or file system structures (files and folders)



An Abstraction can be implemented by an abstraction implementation, and this implementation does not depend on any concrete implementers of the Implementer interface. Extending the abstraction does not affect the Implementor. Also extending the Implementor has no effect on the Abstraction.
 


Example 1 . Where remote control is used 


1:  //Implementer   
2:  public interface TV {  
3:       public void on();  
4:       public void off();   
5:       public void tuneChannel(int channel);  
6:  }  
  And then we create two specific implementations - one for Sony and one for Samsung

1:  // Concrete Implementer   
2:  public class Sony implements TV {  
3:       @Override  
4:       public void off() {  
5:             System.out.println(" Sony Companies TV switched OFF ");  
6:       }  
7:       @Override  
8:       public void on() {  
9:            System.out.println(" Sony Companies TV switched ON ");  
10:       }  
11:       @Override  
12:       public void tuneChannel(int channel) {  
13:            System.out.println(" Sony Companies TV Tune to channel number "+channel);  
14:       }  
15:  }  

These classes deal with the specific implementations of the TV from each vendor. 

1:  3)     //Concrete Implementor   
2:  public class Samsung implements TV {  
3:       @Override  
4:       public void off() {  
5:             System.out.println(" Samsung Companies TV switched OFF ");  
6:       }  
7:       @Override  
8:       public void on() {  
9:            System.out.println(" Samsung Companies TV switched ON ");  
10:       }  
11:       @Override  
12:       public void tuneChannel(int channel) {  
13:            System.out.println(" Samsung Companies TV Tune to channel number "+channel);  
14:       }  
15:  }


Example 2 :  Vehicle Demo 
 Suppose we have a Vehicle class. We can extract out the implementation of the engine into an Engine class. We can reference this Engine implementor in our Vehicle via an Engine field. We'll declare Vehicle to be an abstract class. Subclasses of Vehicle need to implement the drive() method. Notice that the Engine reference can be changed via the setEngine() method.
 
1:  public abstract class Vehicle {  
2:       Engine engine;  
3:       int weightInKilos;  
4:       public abstract void drive();  
5:       public void reportOnSpeed(int horsepower) {  
6:            int ratio = weightInKilos / horsepower;  
7:            if (ratio < 3) {  
8:                 System.out.println("The vehicle have fast speed.");  
9:            } else if ((ratio >= 3) && (ratio < 8)) {  
10:                 System.out.println("The vehicle have average speed.");  
11:            } else {  
12:                 System.out.println("The vehicle have slow speed.");  
13:            }  
14:       }  
15:       public Engine getEngine() {  
16:            return engine;  
17:       }  
18:       public void setEngine(Engine engine) {  
19:            this.engine = engine;  
20:       }  
21:  }  

Our implementer interface is the Engine interface, which declares the go() method
BigBus is a subclass of Vehicle. It has a weight of 3000 kg. Its drive() method displays a message, calls the engine's go() method, and then calls reportOnSpeed() with the horsepower of the engine to report on how fast the vehicle is moving.

1:  public class BigBus extends Vehicle {  
2:       public BigBus(Engine engine) {  
3:            this.weightInKilos = 3000;  
4:            this.engine = engine;  
5:       }  
6:       @Override  
7:       public void drive() {  
8:            System.out.println("\nThe big bus is driving");  
9:            int horsepower = engine.go();  
10:            reportOnSpeed(horsepower);  
11:       }  
12:  }  

SmallCar is similar to BigBus but is much lighter.

1:  public class SmallCar extends Vehicle {  
2:       public SmallCar(Engine engine) {  
3:            this.weightInKilos = 600;  
4:            this.engine = engine;  
5:       }  
6:       @Override  
7:       public void drive() {  
8:            System.out.println("\nThe Small Car is driving");  
9:            int horsepower = engine.go();  
10:            reportOnSpeed(horsepower);  
11:       }  
12:  }  

A BigEngine implements Engine. BigEngine has 600 horsepower. It's go() method reports that it is running and returns the horsepower.  

1:  public class BigEngine implements Engine {  
2:       int horsepower;  
3:       public BigEngine() {  
4:            horsepower = 350;  
5:       }  
6:       @Override  
7:       public int go() {  
8:            System.out.println("The big engine is running");  
9:            return horsepower;  
10:       }  
11:  }  

SmallEngine is similar to BigEngine. It has only 100 horsepower.


1:  public class SmallEngine implements Engine {  
2:       int horsepower;  
3:       public SmallEngine() {  
4:            horsepower = 100;  
5:       }  
6:       @Override  
7:       public int go() {  
8:            System.out.println("The small engine is running");  
9:            return horsepower;  
10:       }  
11:  }  

 
The BridgeDemo class demonstrates our bridge pattern. We create a BigBus vehicle with a SmallEngine implementor. We call the vehicle's drive() method. Next, we change the implementor to a BigEngine and once again call drive(). After this, we create a SmallCar vehicle with a SmallEngine implementor. We call drive(). Next, we change the engine to a BigEngine and once again call drive().


The big bus is driving
The small engine is running
The vehicle is going at a slow speed.

The big bus is driving
The big engine is running
The vehicle is going at a slow speed.

The Small Car is driving
The small engine is running
The vehicle is going an average speed.

The Small Car is driving
The big engine is running
The vehicle is going at a fast speed.
 

Notice that we were able to change the implementor (engine) dynamically for each vehicle. These changes did not affect the client code in BridgeDemo. In addition, since BigBus and SmallCar were both subclasses of the Vehicle abstraction, we were even able to point the vehicle reference to a BigBus object and a SmallCar object and call the same drive() method for both types of vehicles.
There you are, designing car remotes for various types of cars. But it’s getting confusing. You have an abstract class that’s extended to create various types of car remotes: those that just control the car alarm, those that start the car remotely, and so on. But you need to deal with various different car types, such as Toyota, Honda, and so on. And to support new remotes that are planned, your abstract Remote class has to change as needed.

As you’d expect, where there are two things that can change, and they’re tied together, there’s a pattern that can help out. The Bridge pattern comes to the rescue by saying that you should separate out the Car type into its own class. The remote will contain a car using a “has-a” relationship so that it knows what kind of car it’s dealing with. This relationship looks like the one shown in Figure below  — the “has-a” connection between the remote and the car type is called the bridge
 

The inspiration here is that when you have an abstraction that can vary,and that’s tied to an implementation that can also vary, you should decouple the two.




 Bridge design pattern in java API



Notes : 
1)      One of the major drawbacks of this pattern is that, in providing flexibility, it increases complexity. There's also possible performance issues with the indirection of messages - the abstraction needs to pass messages along to the implementer for the operation to get executed.

2)      Bridge design pattern can be used when both abstraction and implementation can have different hierarchies independently and we want to hide the implementation from the client application.

3) What is the basic problem being solved by the Bridge pattern ?
    The derivations of an abstract class must use multiple implementations without causing an explosion in the number of classes.  


What is the intent of Bridge pattern ?  

Decouple an abstraction from its implementation so that the two can vary independently   



4)      Proxy, Decorator, Adapter, and Bridge are all variations on "wrapping" a class. But their uses are different.
Proxy could be used when you want to lazy-instantiate an object, or hide the fact that you're calling a remote service, or control access to the object.
Decorator is also called "Smart Proxy." This is used when you want to add functionality to an object, but not by extending that object's type. This allows you to do so at runtime.
Adapter is used when you have an abstract interface, and you want to map that interface to another object which has similar functional role, but a different interface.
Bridge is very similar to Adapter, but we call it Bridge when you define both the abstract interface and the underlying implementation. I.e. you're not adapting to some legacy or third-party code, you're the designer of all the code but you need to be able to swap out different implementations. 

5) Facade is a higher-level (read: simpler) interface to a subsystem of one or more classes. Think of Facade as a sort of container for other objects, as opposed to simply a wrapper.
6)      Bridge and Adapter both point at an existing type. But the bridge will point at an abstract type, and the adapter might point to a concrete type.
7)      The bridge will allow you to pair the implementation at runtime, whereas the adapter usually won't.











 

No comments: