Does the Bridge Pattern decouples an abstraction from implementation?
Asked Answered
L

3

19

I learned Bridge pattern from different articles and I have implemented that as per my understanding . One thing that is confusing me is bridge pattern says

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

what is meaning of this statement? Is implementation resides at in separate jar ?

what is meaning of vary independently statement ?

considering the provided journaldev article, elaborate the answer.

Any help is greatly appreciated.

Leanto answered 29/1, 2016 at 8:8 Comment(0)
D
30

BridgePattern decouples an abstraction from its implementation.

Abstraction and Implementation can vary independently since the concrete class does not directly implement Abstraction ( interface)

Implementation never refers Abstraction. Abstraction contains Implementation interface as a member (through composition).

Coming back to your question regarding the example code in [journaldev][4] article :

Shape is Abstraction

Triangle is RedefinedAbstraction

Color is Implementor

RedColor is ConcreteImplementor

A concrete Shape object : Triangle extends Shape but does not implement the Color interface.

public class Triangle extends Shape{
}

RedColor and GreenColor actually implement the Color interface.

The Concrete Shape object (Triangle) is independent of implementing abstraction (i.e. Color interface).

Shape tri = new Triangle(new RedColor());

Here Triangle contains a concrete Color object ( Composition). If there is a change in the Color abstraction (interface), RedColor and GreenColor are responsible for implementing the abstraction of Color interface.

Shapes like Triangle is not affected by changes in contract to the Color interface. So the Color interface can vary independently. This is possible because Shape holds the contract that uses Composition rather than implementation.

Example code to understand the pattern better:

Example code:

/* Implementor interface*/
interface Gear{
    void handleGear();
}

class VehicleAttributes{
    String name;
    String engineID;
    String chasisNumber;
    int seats;
    int engineCapacity;
    double height;
    double length;
}

/* Concrete Implementor - 1 */
class ManualGear implements Gear{
    public void handleGear(){
        System.out.println("Manual gear");
    }
}
/* Concrete Implementor - 2 */
class AutoGear implements Gear{
    public void handleGear(){
        System.out.println("Auto gear");
    }
}
/* Abstraction (abstract class) */
abstract class Vehicle {
    Gear gear;
    /* Mutable state of Vehicle */
    VehicleAttributes attributes;
    public Vehicle(Gear gear){
        this.gear = gear;
    }
    abstract void addGear();
    public void setVehicleAttributes(VehicleAttributes attributes){
        this.attributes = attributes;
    }
    
}
/* RefinedAbstraction - 1*/
class Car extends Vehicle{
    public Car(Gear gear){
        super(gear);
        // initialize various other Car components to make the car
    }
    public void addGear(){
        System.out.print("Car handles ");
        gear.handleGear();
    }
}
/* RefinedAbstraction - 2 */
class Truck extends Vehicle{
    public Truck(Gear gear){
        super(gear);
        // initialize various other Truck components to make the car
    }
    public void addGear(){
        System.out.print("Truck handles " );
        gear.handleGear();
    }
}
/* Client program */
public class BridgeDemo {    
    public static void main(String args[]){
        Gear gear = new ManualGear();
        Vehicle vehicle = new Car(gear);
        vehicle.addGear();
        
        gear = new AutoGear();
        vehicle = new Car(gear);
        vehicle.addGear();
        /* Create specific properties of Car in attributes */
        //vehicle.setVehicleAttributes(attributes);
        
        gear = new ManualGear();
        vehicle = new Truck(gear);
        vehicle.addGear();
        /* Create specific properties of Truck in attributes */
        //vehicle.setVehicleAttributes(attributes);
        
        gear = new AutoGear();
        vehicle = new Truck(gear);
        vehicle.addGear();
        /* Create specific properties of Truck in attributes */
        //vehicle.setVehicleAttributes(attributes);
    }
}

output:

Car handles Manual gear
Car handles Auto gear
Truck handles Manual gear
Truck handles Auto gear

Explanation:

  1. Vehicle is an abstraction.
  2. Car and Truck are two concrete implementations of Vehicle.
  3. Vehicle defines an abstract method : addGear().
  4. Gear is implementor interface
  5. ManualGear and AutoGear are two implementations of Gear
  6. Vehicle contains implementor interface rather than implementing the interface. Compositon of implementor interface is crux of this pattern : It allows abstraction and implementation to vary independently.
  7. Car and Truck define implementation ( redefined abstraction) for abstraction : addGear() : It contains Gear - Either Manual or Auto
Deport answered 29/1, 2016 at 8:20 Comment(9)
very well explained ,but there is one more confusion after considering this example let assume there is no bridge pattern and you are simply making inheritance to achieve target for example RedColor class extends triangle and provide its implementation than what would be the effect if there is some change in requirement???Leanto
Do you mean Triangle extends RedColor or RedColor extends Triangle?Deport
with current code, Triangle can have 100+ concrete colors, which implement Color abstraction.Deport
RedColor extends triangle similarly GreenColor extends triangle than what would be the effect if requirement changes r new feature is added ? mean to say that we have to change the code ? I simply wants to understand that in most articles it says that in longer run if there is a new requirement you have to change the code that would effect other in terms of tested classes?Leanto
It should be reverse. Triangle extends Color and you can pass RedColor or GreenColor in constructor. If you add one method in Color interface, you have to change Triangle now ( in absence of Bridge pattern). With Bridge pattern, which has composition of Color with Triangle don't have these headaches. Now Concrete Colors have to implement changes in Color contract.Deport
@Ravindrababu, you've given the accepted answer here, so what more are you looking for by offering a bounty?Dressing
what is meant by varying of the two independently?Kazmirci
what is meant by varying of the two independently? Or to be specific, what is meant by changing an interface. because simply changing a class happens all the timeKazmirci
In above example, you can change Shape and Color independently.Deport
O
5

This statement simply means, that you can switch implementor, to which abstraction points to, in run-time and everything should work (like in Strategy Pattern; but in Strategy Pattern, only strategies are abstract). It can be also understood as separating two classes, so that they don't have to know about each other more than just their interfaces.

Oconnell answered 29/1, 2016 at 8:17 Comment(0)
S
0

For me Bridge is not really the most foremost DP in the GOF bible, since it is mostly a derivative of Strategy. As some other patterns that have not aged so well (factory method?) it implies more inheritance with abstract classes holding behavior than other patterns, hence is less generally applicable.

It's mostly Strategy doing the big work, but a major issue with Strategy is that the strategy often needs knowledge about its context.

In some languages this leads to strategies being declared friend of the context, or strategies defined as internal classes in Java.

This means that the context often ends up with knowledge of existence of the various concrete strategies. You can avoid this by using a setStrategy() function, but the reverse dependency from concrete strategy to context usually survives, due to efficiency reasons (you want to manipulate the context's data structures directly).

This issue is kind of solved by Bridge, as the context of Strategy is now abstract, but still a class a priori, since it has at least the code for Strategy. It should usually define an access API sufficient for the concrete Strategies to work with, possibly with holes i.e. abstract methods. You put an occurrence of AbstractContext in the signature of the operations on AbstractStragey and you're good.

So in my point of view, Bridge completes Strategy by making the Context concrete enough for the strategies to work, but still abstract enough that it can be orthogonally refined w.r.t. concrete strategies (with feedback effects when implementing abstract API of the context that the concrete strategies actually use).

A simpler way of seeing bridge is to say that the AbstractStrategy operations should always take abstractions as parameters rather than really knowing intimately their context.

To answer the OP question more precisely :

what is meaning of this statement? Is implementation resides at in separate jar ?

Yes, indeed, typically you could define the Abstraction and Implementor in a package "base" (tey could be interfaces). The concrete Implementors can each reside in a package "implXX". The concrete context can reside in separate packages "contXX". There are no cycles in the dependency graph, everybody depends on base, new "contXX" and "implXX" can be defined independently (no dependencies at all between them) thus the bold statement in the OP.

what is meaning of vary independently statement ?

Think of an editor plugin in eclipse; it must handle the actions on buttons and clicks (like a strategy), but the actual action the strategy needs to do is act on the editor state itself (e.g. "highlight text"). You define what an editor possesses in an abstract way, including the fact that it has Handler for clics and keypresses as well as highlighting and navigation features, even these can be overriden by concrete editors (flash instead of highlight). That's a bridge, you can define new editors and new handler independently.

With some dependency injection (e.g. Google guice) or some manual factory code or component orientation to cleanly setStrategy from outside you get very low coupling of the various parts of the application.

considering the provided journaldev article, elaborate the answer.

honestly I think this is a not the best application of the DP since the Color implementations don't seem to care much about their context. You should use a Decorator here as Color is an independent concern from Shape.

Have a look a at these slides for a solution with a Decorator (partly in French, sorry). https://www-licence.ufr-info-p6.jussieu.fr/lmd/licence/2015/ue/3I002-2016fev/cours/cours-9.pdf (slides 16-18) based on example introduced here : https://www-licence.ufr-info-p6.jussieu.fr/lmd/licence/2015/ue/3I002-2016fev/cours/cours-4.pdf slides 10 to 15.

On that example, we would need Bridge if "updateInertie" was member of Forme, which does not sound preposterous. Again Bridge emerges more as a combination of other patterns.

Spelaean answered 10/6, 2016 at 22:56 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.