Before we look at bridging patterns, let’s try to understand what this name means. “Bridge Design Pattern” refers to connecting references. In GoF’s Book Design Patterns, it is described as “decoupling abstraction and implementation so that they can change independently”. Abstraction and implementation decoupling My understanding is that replacing inheritance with connections makes the parent class less intrusive to the child class. Another way of saying it is the decoupling of the dimension of the attribute of a thing. For example, if I want to buy a mobile phone now, FIRST OF all, I have requirements on the color of the mobile phone, secondly, I also have requirements on the pixel of the camera, and finally, I may have some requirements on the brand of the mobile phone. At this time, the object of mobile phone is extracted from three dimension attributes. If the programming level is implemented in accordance with the traditional inheritance way, we use the mobile phone that dynamically obtains the combination of attributes of different dimensions, it will cause class explosion. Extensibility is also a problem if you add attributes in other dimensions. The following is to explain the bridge design philosophy through specific structure and mode.

Definition and characteristics of bridge mode

The Bridge pattern is defined as follows:

  • Separate the abstraction from the implementation so that they can vary independently. It is realized by using combinatorial relation instead of inheritance relation, thus reducing the coupling degree of abstraction and realization of these two variable dimensions.

Structure and implementation of bridge pattern

Pattern structure:

  • Abstraction character: Defines the abstract class and contains a reference to the implemented object.
  • The Refined Abstraction character: is a subclass of the Abstraction character that implements the business methods in the parent class and implements the business methods in the character through composite relationship calls.
  • Implementor Role: Defines an interface that implements the role for extended abstract role invocation.
  • Concrete Implementor: Provides the Concrete implementation of the interface for implementing the role.

Structure:

Code example: Here according to the way of different dimension attributes, try to facilitate you to understand the use of bridge mode; At present, I want to buy a new mobile phone, and there are requirements for the color and brand of the phone. The bridge mode simulates the scenario where I choose a mobile phone.

  • Implementor color
public interface Color {
	
	String showColor(a);
}
Copy the code
  • Concrete Implementor

I’m going to simulate two colors here color 1.

public class BlackColor implements Color{

	@Override
	public String showColor(a) {
		return "Black"; }}Copy the code

2 colors

public class SilverColor implements Color{

	@Override
	public String showColor(a) {
		return "Silver"; }}Copy the code
  • Abstraction of cell phone character and color reference
public abstract class AbstractMobile {
  // Implement the role
  protected Color color;
  
  protected AbstractMobile(Color color) {
      this.color = color;
  }
  
  /** * mobile phone brand */
  public abstract void brand(a);
}
Copy the code
  • Concrete Implementor

Two mobile phone brands are realized here: 1. Brand 1Huawei

public class HuaweiMobile extends AbstractMobile{

	protected HuaweiMobile(Color color) {
		super(color);
	}
	
	@Override
	public void brand(a) {
		System.out.println(color.showColor() + "Huawei mobile"); }}Copy the code

Brand 2 Iphone

public class Iphone extends AbstractMobile {

	protected Iphone(Color color) {
		super(color);
	}
	
	@Override
	public void brand(a) {
		System.out.println(color.showColor() + "IPhone mobile"); }}Copy the code
  • Use the client
public class Client {
	public static void main(String[] args) {
		// Want to get black iPhone
		Color color = new BlackColor();
		AbstractMobile iphone = newIphone(color); iphone.brand(); }}Copy the code

Execution Result:

Black IPhone mobileCopy the code

Case structure diagram:

Bridge mode in the source code application

1.JDBC connection with Driver as bridge object:

// Connect to the database using native JDBC
// 1. Reflection loads the driver class
Class.forName("com.mysql.jdbc.Driver");
// 2. Obtain the Connection
conn = DriverManager.getConnection(DB_URL,USER,PASS);
// 3. Obtain the object Statement of the SQL Statement
Statement stmt = conn.createStatement();
/ /...
Copy the code

Let’s first look at how the DriverManager class can get the connection to the database, and when the driver is registered. The mysql Driver is used as an example

public class Driver extends NonRegisteringDriver implements java.sql.Driver {
    public Driver(a) throws SQLException {}static {
        try {
            // Register the driver
            DriverManager.registerDriver(new Driver());
        } catch (SQLException var1) {
            throw new RuntimeException("Can't register driver!"); }}}Copy the code

Registration drive DriverManager. RegisterDriver (new Driver ()), and then look at the DriverManager. GetConnection () method.

 // List of registered JDBC drivers 
 // The registration in Driver is registered to this collection
    private final static CopyOnWriteArrayList<DriverInfo> registeredDrivers = new CopyOnWriteArrayList<>();  
  
// Get the connection
private static Connection getConnection( String url, java.util.Properties info, Class
        caller) throws SQLException {
/ / a little
for(DriverInfo aDriver : registeredDrivers) {
            // If the caller does not have permission to load the driver then
            // skip it.
       if(isDriverAllowed(aDriver.driver, callerCL)) {
                try {
                    println(" trying " + aDriver.driver.getClass().getName());
                    // Get the specified connection according to the driver
                    Connection con = aDriver.driver.connect(url, info);
                    if(con ! =null) {
                        // Success!
                        println("getConnection returning " + aDriver.driver.getClass().getName());
                        return(con); }}catch (SQLException ex) {
                    if (reason == null) { reason = ex; }}}else {
                println(" skipping: " + aDriver.getClass().getName());
            }
    
    / / a little
    
Copy the code

Driver connect() method, through different Driver classes will call different connections, each database vendor only need to follow their own way to implement this method, can complete the program JDBC connection. This might be a little hard to understand, but abstraction and implementation are decoupled and can change independently, so we are bridging the design idea, so the abstraction here should be our specific JDBC specification, regardless of the specific implementation vendor, whether it’s mysql or Oracle, they are all based on the JDBC specification. Driver is equivalent to the implementation of each vendor, the implementation here is not the implementation we say in the concept, the concept of the implementation is independent change, will not affect the specification, DriverManager is our bridge, assembly abstract part, here is the implementation of each vendor Driver class, JDBC all operations, All delegate to the Driver.

Advantages and disadvantages of the bridge mode

The advantages of the Bridge mode are:

  • Abstraction and implementation separation, strong ability to expand
  • In line with the open and close principle
  • In line with the principle of composite reuse
  • The implementation details are transparent to the customer

The disadvantage is that since the aggregation relationship is established at the abstraction level, developers are required to design and program for abstraction, and can correctly identify the two dimensions of independent change in the system, which increases the difficulty of understanding and designing the system.

Application scenarios of bridge mode

When there are two or more varying dimensions within a class, using the bridge pattern can decouple these varying dimensions and stabilize the high-level code architecture.

The bridge mode usually applies to the following scenarios.

  • When a class has two independently varying dimensions and both dimensions need to be extended.
  • When a system does not want to use inheritance or the number of system classes increases dramatically because of multi-level inheritance.
  • When a system needs to add more flexibility between the abstract and embodied roles of the component.

A common use of the bridge pattern is substitution inheritance. Inheritance has many advantages, such as abstraction, encapsulation, polymorphism, etc., parent class encapsulates commonality, and subclass implements features. Inheritance is a great way to reuse code (encapsulation), but it is also a major disadvantage of inheritance.

Because the parent class owns methods, the subclass inherits them, whether the subclass needs them or not, this means that inheritance is intrusive (the parent code invents the subclass) and can cause subclass bloat. Therefore, in design patterns, it is a principle to use composition/aggregation in preference to inheritance.