An introduction to the Bridge pattern of Java design patterns

  • 2020-04-01 03:41:37
  • OfStack

Bridge definition: separates abstractions and behaviors, independently, but dynamically.

Why use bridge mode

Typically, when an abstract class or interface has multiple concrete implementations (concrete subclasses), there are two possible relationships between those concrete:

1. These multiple concrete implementations are juxtaposed. For example, in the example of piling, there are two concrete classes: square pile and circular pile. The piles on the two shapes are side-by-side, there is no conceptual duplication, so we just use inheritance.
2. In practice, it is often possible to overlap these concrete classes conceptually. So we need to separate the abstract common part from the behavior common part, which was originally intended to be in an interface, and now we need to design two interfaces to place the abstraction and behavior separately.

For example, a cup of coffee can be medium or large, with or without milk. If we use simple inheritance, these four concrete implementations (medium and large cups with milk and no milk) have overlapping concepts, because there are medium cups with milk and medium cups without milk. If we implement two inheritance in the medium cup layer, it is obviously chaotic and extremely poor scalability. Let's use the Bridge pattern to implement it.

How to implement the bridge pattern

Take the example of coffee mentioned above. We originally intended to design just one interface (an abstract class), but after using the Bridge pattern, we needed to separate the abstraction from the behavior, where milk and no milk belong to the behavior, and we abstracted them into a specialized behavior interface.

First look at the interface code for the abstract part:


public abstract class Coffee{
 CoffeeImp coffeeImp;
 public void setCoffeeImp() {
  this.CoffeeImp = CoffeeImpSingleton.getTheCoffeImp();
 }
 public CoffeeImp getCoffeeImp() {return this.CoffeeImp;}
 public abstract void pourCoffee();
}

Where CoffeeImp is the behavior interface with or without milk, see its code as follows:


public abstract class CoffeeImp{
 public abstract void pourCoffeeImp();
}

Now that we have two abstract classes, let's inherit them and implement concrete class:

//Medium < br / > public class MediumCoffee extends Coffee{
 public MediumCoffee() {setCoffeeImp();}
 public void pourCoffee(){
  CoffeeImp coffeeImp = this.getCoffeeImp();
  // We use the number of repetitions to indicate whether it is medium or large , repeat 2 Time is Medium < br / >   for (int i = 0; i < 2; i++){
   coffeeImp.pourCoffeeImp();
  }
 }
}


//Big cup public class SuperSizeCoffee extends Coffee{
 public SuperSizeCoffee() {setCoffeeImp();}
 public void pourCoffee(){
  CoffeeImp coffeeImp = this.getCoffeeImp();
  // We use the number of repetitions to indicate whether it's a medium or a medium Big cup , repeat 5 Time is Big cup
  for (int i = 0; i < 5; i++){
   coffeeImp.pourCoffeeImp();
  }
 }
}

The above is the concrete implementation of medium cup and large cup respectively. The following is the inheritance of behavior CoffeeImp:


//White < br / > public class MilkCoffeeImp extends CoffeeImp{
 MilkCoffeeImp() {}
 public void pourCoffeeImp(){
  System.out.println(" With delicious milk ");
 }
} // Don't White < br / > public class FragrantCoffeeImp extends CoffeeImp{
 FragrantCoffeeImp() {}
 public void pourCoffeeImp(){
  System.out.println(" nothing , fragrance ");
 }
}

We have the basic framework of the Bridge model set up, and don't forget the definition: dynamic combination, we can now drink at least four kinds of coffee:

1. Medium with milk
2. Medium without milk
3. Large glass with milk
4. Large glass with no milk

To see how this can be done dynamically, let's design a Singleton to hold the current CoffeeImp before using it.


public class CoffeeImpSingleton{
 private static CoffeeImp coffeeImp;
 public CoffeeImpSingleton(CoffeeImp coffeeImpIn)
 {this.coffeeImp = coffeeImpIn;}
 public static CoffeeImp getTheCoffeeImp(){
  return coffeeImp;
 }
}
Look at a medium glass with milk And a large glass with milk How it came out: //Take out the milk
CoffeeImpSingleton coffeeImpSingleton = new CoffeeImpSingleton(new MilkCoffeeImp()); //Medium cup with milk
MediumCoffee mediumCoffee = new MediumCoffee();
mediumCoffee.pourCoffee(); //Large cup with milk
SuperSizeCoffee superSizeCoffee = new SuperSizeCoffee();
superSizeCoffee.pourCoffee();

Note: the execution classes of the Bridge pattern, such as CoffeeImp and Coffee, are one-to-one relationships, and proper creation of CoffeeImp is the key to this pattern.

The Bridge pattern is applied in ejbs

There is a Data Access Object (DAO) pattern in the EJB, which separates business logic from specific Data resources because different databases have different database operations. The behavior of operating different databases is independently abstracted into a behavior interface DAO, as follows:

1.Business Object (similar to Coffee)
Implement abstract business operations such as finding a user to place all orders. All involving database operations use DAOImplementor.
 
2.Data Access Object (similar to CoffeeImp)
Some abstract operations on database resources.
 
3.DAOImplementor such as OrderDAOCS, OrderDAOOracle, OrderDAOSybase(similar to MilkCoffeeImp FragrantCoffeeImp)
For specific database operations, such as "INSERT INTO "statements, OrderDAOOracle is Oracle OrderDAOSybase is Sybase database.
 
4. Database (Cloudscape, Oracle, or Sybase database via JDBC API)


Related articles: