[Design Mode] Adapter Mode and Bridge Mode

adapter pattern

Adapter mode: It is to change the interface of a class into another interface expected by the client, so that the interfaces that could not work together because of the interface mismatch can work normally. Belongs to Structural Patterns

For example, I have a brand A bottle, and then bought a B brand nipple, what should I do if it doesn’t match? Just buy another converter

In software development, basically any problem can be solved by adding an intermediate layer (abstraction)

The adapter pattern generally includes three roles:

Target role Target: that is, the interface
source role that the client expects Adaptee: the existing interface, the content meets the requirements, but the client cannot access
the adapter Adapter:

Adapters can be divided into three categories: class adapters, object adapters, and interface adapters (the core idea is to make Adapter have the characteristics of Target and Adaptee at the same time)

Taking the voltage in life as an example, we need to convert the civilian 220V AC into 5V DC that the mobile phone can receive.

public interface IDV5VTarget {
    
    
    int output5V();
}
public class AC220VAdaptee {
    
    
    public int output220V() {
    
    
        int output = 220;
        System.out.println("输出电压:" + output + "V");
        return output;
    }
}

Class adapter: based on inheritance, Adapter inherits Adaptee

public class ClassAdapter extends AC220VAdaptee implements IDV5VTarget{
    
    

    @Override
    public int output5V() {
    
    
        int output = super.output220V()/44;
        System.out.println("转换后的电压为" + output + "V");
        return output;
    }
}

Object Adapter: Based on combination implementation, Adapter holds Adaptee object

public class ObjectAdpater implements IDV5VTarget{
    
    

    private AC220VAdaptee ac220VAdaptee;

    public ObjectAdpater(AC220VAdaptee ac220VAdaptee) {
    
    
        this.ac220VAdaptee = ac220VAdaptee;
    }

    @Override
    public int output5V() {
    
    
        int output =  this.ac220VAdaptee.output220V()/44;
        System.out.println("转换后的电压为:" + output + "V");
        return output;
    }
}

Interface adapter: If the interface defines too many methods, the interface adapter allows us to implement only the methods that need to be converted (if the interface is directly implemented, there will be many empty implementation methods)

Summarize

advantage :

  1. Through the adapter mode, the client can use a unified set of interfaces, which makes the implementation more concise and clear
  2. Reuse existing classes and codes to reduce the amount of code changes

scenes to be used

The adapter mode is used for adaptation, which converts incompatible interfaces into compatible interfaces, so that classes that could not work together due to incompatible interfaces can work together. Often used to compensate for flaws in interface design.

The general usage scenarios are as follows:

  • Encapsulate flawed interface design
  • Unify the interface design of multiple classes
  • Replace dependent external systems
  • Compatible with the old version interface
  • Adapt to data in different formats

bridge mode

The bridge mode is to separate the abstract part from its concrete implementation, so that they can all change independently without interfering with each other, which belongs to the structural mode.
The core of the bridge pattern is to decouple abstraction and implementation.

The "abstract" here does not refer to "abstract classes" or "interfaces", but a set of abstracted "class libraries", which only contain skeleton codes, and the real business logic needs to be delegated to the defined "Realize" to complete. The "implementation" in the definition is not an "interface implementation class", but a set of independent "class libraries". "Abstract" and "implementation" are developed independently and assembled together through the combination relationship between objects

The application of the classic bridge mode is our JDBC driver

{
    
    
	Class.forName("com.mysql.jdbc.Driver");//加载及注册JDBC驱动程序
	String url = "jdbc:mysql://localhost:3306/db?
	Connection con = DriverManager.getConnection(url);
	Statement stmt = con.createStatement()String query = "select * from test_table";
	ResultSet rs=stmt.executeQuery(query);
	while(rs.next()) {
    
    
		rs.getString(1);
		rs.getInt(2);
	}
}

If we use a different database, just com.mysql.jdbc.Driverreplace it oracle.jdbc.driver.OracleDriverwith

We can see how jdbc is implemented

public class Driver extends NonRegisteringDriver implements java.sql.Driver {
    
    
    public Driver() throws SQLException {
    
    
    }

    static {
    
    
        try {
    
    
            DriverManager.registerDriver(new Driver());
        } catch (SQLException var1) {
    
    
            throw new RuntimeException("Can't register driver!");
        }
    }
}

Class.forName("com.mysql.jdbc.Driver")Here is to execute the static code block of the Driver, register the Driver in the DriverManager, and then the connection we get from the DriverManager is actually obtained by using our registered driver

 public static Connection getConnection(String url,
        java.util.Properties info) throws SQLException {
    
    

        return (getConnection(url, info, Reflection.getCallerClass()));
    }

  private static Connection getConnection(
        //...
        for(DriverInfo aDriver : registeredDrivers) {
    
    
            if(isDriverAllowed(aDriver.driver, callerCL)) {
    
    
                try {
    
    
                    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());
            }

        }
        throw new SQLException("No suitable driver found for "+ url, "08001");
    }

The bridge mode mainly includes four roles
abstraction (Abstraction) role : define an abstract class, and include a reference to the realized object.
Extended abstraction (Refined Abstraction) role : it is a subclass of the abstraction role, implements the business method in the parent class, and calls the business method in the realized role through the composition relationship.
Implementor role : Define the interface of the implementor role, which can be called by the extended abstract role.
Concrete Implementor role : Gives the concrete implementation of the implementor role interface.

The specific class diagram is as follows:
insert image description here
Taking the alarm of daily work as an example, our alarm message can be sent by email, SMS, or telephone. According to the importance of the alarm, it can be divided into urgent, important, and common. Alarm messages can be split according to two different dimensions of sending method and urgency

First define an interface for sending messages and an abstract role for bridging

public interface IMessageSender {
    
    

    void sendMessage(String message);
}

public abstract class AbstractMessage {
    
    
    private IMessageSender messageSender;

    public AbstractMessage(IMessageSender messageSender) {
    
    
        this.messageSender = messageSender;
    }

    public void sendMessage(String message) {
    
    
        this.messageSender.sendMessage(message);
    }
}
public class EmailMessageSender implements IMessageSender{
    
    

    @Override
    public void sendMessage(String message) {
    
    
        System.out.println("发送邮件"+ message + ".....");
    }
}

public class PhoneMessageSender implements IMessageSender{
    
    

    @Override
    public void sendMessage(String message) {
    
    
        System.out.println("拨打电话:" + message + ".....");
    }
}

public class SmsMessageSender implements IMessageSender{
    
    

    @Override
    public void sendMessage(String message) {
    
    
        System.out.println("发送短信" + message + ".....");
    }
}
public class NormalMessage extends AbstractMessage{
    
    

    public NormalMessage(IMessageSender messageSender) {
    
    
        super(messageSender);
    }

    @Override
    public void sendMessage(String message) {
    
    
        super.sendMessage("普通" + message);
    }
}
public class UrgencyMessage extends AbstractMessage {
    
    

    public UrgencyMessage(IMessageSender messageSender) {
    
    
        super(messageSender);
    }

    @Override
    public void sendMessage(String message) {
    
    
        super.sendMessage("紧急" + message);
    }
}

Summarize

Bridge mode is suitable for the following scenarios:

  1. A class has two (or more) dimensions that vary independently, and both (or more) dimensions need to be expanded independently
  2. The system does not want to use inheritance or the number of classes increases sharply due to multi-level inheritance
  3. Need to add more flexibility between abstraction and concrete implementation

The code implementation of the bridge mode is very simple, but it is a little difficult to understand, and the application scenarios are relatively limited, and it is not so commonly used in projects.

Guess you like

Origin blog.csdn.net/qq_35448165/article/details/129413195