1. Summary of the foregoing

“Make up” ongoing: Design pattern series

2. Bridge mode

My last article on design patterns has me, a terminal procrastinator, kicking the can down the road to the last day of 2020.

This is the last, but not the most difficult, pattern. Two of the more complex patterns have already been covered, the visitor pattern and the interpreter pattern.

So what is bridge mode?

2.1 define

Bridge Pattern, also called Bridge Pattern, is a relatively simple Pattern, which is defined as follows: (acts as a abstraction from its implementation so that the two can vary independently.)

The key point of bridge mode is “decoupling”. How to make them decoupled is the key point of bridge mode.

2.2 General class diagram

  • Abstraction character: Defines the behavior of the character while keeping a reference to the implemented character, which is typically an abstract class
  • Implementor: An interface or abstract class that defines the required behavior and properties of the role.
  • RefinedAbstraction character: RefinedAbstraction character is amended.
  • ConcreteImplementor: Methods and properties that implement interface or abstract class definitions.

The bridge pattern has a few awkward nouns, but the core sentence is: abstract roles reference implementation roles, or the partial implementation of abstract roles is done by implementation roles.

2.3 Common Code

Implement roles:

public interface Implementor {
    // Basic method
    void doSomething(a);
    void doAnything(a);
}
Copy the code

Concrete roles:

public class ConcreteImplementor1 implements Implementor {
    @Override
    public void doSomething(a) {}@Override
    public void doAnything(a) {}}public class ConcreteImplementor2 implements Implementor {
    @Override
    public void doSomething(a) {}@Override
    public void doAnything(a) {}}Copy the code

Abstract characters:

public abstract class Abstraction {
    // Define a reference to the implemented role
    private Implementor impl;
    // Constraint subclasses must implement this constructor
    public Abstraction(Implementor impl){
        this.impl = impl;
    }
    // Own behavior and attributes
    public void request(a){
        this.impl.doSomething();
    }
    // Get the implemented role
    public Implementor getImpl(a){
        returnimpl; }}Copy the code

Concrete abstract characters:

public class RefinedAbstraction extends Abstraction {
    // overwrite the constructor
    public RefinedAbstraction(Implementor impl) {
        super(impl);
    }
    // Fix the behavior of the parent class
    @Override
    public void request(a){
        // Business processing
        super.request();
        super.getImpl().doAnything(); }}Copy the code

Client class:

public class Client {
    public static void main(String[] args) {
        // Define an implementation role
        Implementor imp = new ConcreteImplementor1();
        // Define an abstract role
        Abstraction abs = new RefinedAbstraction(imp);
        // Execute the lineabs.request(); }}Copy the code

2.4 the advantages

  1. Separation of abstraction and implementation: The bridge pattern is entirely a design pattern proposed to address the shortcomings of inheritance.
  2. Excellent ability to expand.
  3. Implementation details are transparent to the customer. The customer does not need to care about the implementation details, which are already encapsulated by the abstraction layer through aggregation relationships.

2.5 disadvantages

It makes the system more difficult to understand and design. Since the aggregation association is built at the abstraction level, developers are required to design and program for abstraction.

2.6 Application Scenarios

  • Scenarios where inheritance is not desired or applicable.
  • Scenarios where interfaces or abstract classes are unstable.
  • Scenarios with high reusability requirements.

3. A simple case

One of the important things to understand in bridging patterns is when to consider which relationships to use: class inheritance and class composition/aggregation. Does the use of class inheritance in programming mean object-oriented programming? Sometimes this is not the case. Java class inheritance is designed to be single-inheritance. I think we just don’t want to make class inheritance too complicated.

Without further ado about class inheritance, let’s take a look at composition/aggregation relationships.

Aggregation is “weak” ownership, as geese can contain geese, but they are not part of geese. Combination embodies the “strong” ownership relationship, or reflects the relationship between the parts and the whole, through a pair of wings combined to form a goose, the wings are the parts, the goose is the whole.

An electric appliance that we use everyday now: mobile phone, mobile phone has mobile phone brand and mobile phone software to wait a moment, each mobile phone brand has much software.

In this case, if the inheritance relationship is used, whether the mobile phone brand or mobile phone software is taken as the parent class, it will have a great influence on the subsequent extension. If we use the bridge mode and use the combination/aggregation of objects, the class diagram is as follows:

Through the UML class structure diagram, we can see that the mobile phone brand and mobile phone software are successfully decoupled. The new function does not affect the mobile phone brand, and the new mobile phone brand does not affect the mobile phone software. The secret lies in the use of aggregation rather than inheritance.

The code is as follows:

Abstract class of mobile phone brand:

public abstract class HandsetBrand {
    protected HandsetSoft soft;
    // Set the phone software
    public void setHandsetSoft(HandsetSoft soft) {
        this.soft = soft;
    }
    / / run
    abstract void run(a);
}
Copy the code

Mobile phone software abstract class:

public abstract class HandsetSoft {
    abstract void run(a);
}
Copy the code

Various mobile phone brand realization categories:

public class HandsetBrandA extends HandsetBrand {
    @Override
    void run(a) {
        super.soft.run(); }}public class HandsetBrandB extends HandsetBrand{
    @Override
    void run(a) {
        super.soft.run(); }}Copy the code

Mobile phone software implementation class:

public class HandsetGame extends HandsetSoft{
    @Override
    void run(a) {
        System.out.println("Running mobile games"); }}public class HandsetAddressList extends HandsetSoft{
    @Override
    void run(a) {
        System.out.println("Run phone contacts"); }}Copy the code

Client class:

public class Client {
    public static void main(String[] args) {
        HandsetBrand ab;

        // Use brand A phone
        ab = new HandsetBrandA();
        System.out.println("Brand A mobile phone:");

        ab.setHandsetSoft(new HandsetGame());
        ab.run();

        ab.setHandsetSoft(new HandsetAddressList());
        ab.run();

        // Use brand B phone
        ab = new HandsetBrandB();
        System.out.println("B brand mobile phone:");

        ab.setHandsetSoft(new HandsetGame());
        ab.run();

        ab.setHandsetSoft(newHandsetAddressList()); ab.run(); }}Copy the code

The result is as follows:

B brand mobile phone: Run mobile games to run mobile phone contactsCopy the code

This article is constantly updated, you can search “Geek excavator” on wechat to read it in the first time, and the key words in reply have all kinds of tutorials PREPARED by me, welcome to read.