An example from life:
Take a car on the road. Both cars and buses can run on highways as well as in the city. You will find that there are different types of vehicles (cars) and different types of environment (roads) on which they drive. In the software system, it is necessary to adapt to the changes of two aspects (different models, different roads). How can we achieve this change?
Summary:
In software systems, some types have two or more dimensional variations due to their own logic, so how to deal with this “multidimensional variation”? How can object-oriented techniques be used to make it easy to vary the type in multiple directions without introducing additional complexity? This uses the Bridge pattern.
Intent of the bridge pattern
Separate the abstract parts from the implementation parts so that they can be changed independently. — GOF, Design Patterns
Implement the above example
1. Use the traditional way, through class inheritance
Code implementation
Class Road {void run() {system.out.println (" path "); } // class Street extends Road {void run() {system.out.println (" Street "); } // extends Road {void run() {system.out.println (" SpeedWay "); }} class CarOnStreet extends Street {void run() {system.out.println (" CarOnStreet extends Street "); }} class CarOnSpeedWay extends SpeedWay {void run() {system.out.println (" CarOnSpeedWay "); }} class BusOnStreet extends Street {void run() {system.out.println (" BusOnStreet extends Street "); }} class BusOnSpeedWay extends SpeedWay {void run() {system.out.println (" BusOnSpeedWay "); }} public static void main(String[] args) {CarOnSpeedWay = new CarOnSpeedWay(); carOnSpeedWay.run(); BusOnStreet = new BusOnStreet(); busOnStreet.run(); }Copy the code
Disadvantages of using inheritance: This design has a lot of problems, first of all, it is contrary to the open closed principle (OCP) composition among at the same time, against the problem of single responsibility, that is, a class has only one factor of the change of the it, and cause changes in here by two factors: changes road type and car type, followed by repeat too much code, different car in different road, you have the same part of the code. Thirdly, the structure of the class is too complex, with too many inheritance relationships and difficult to maintain. The most deadly one is poor scalability. If the change changes along the two dimensions of vehicle type and road type, we can see that the structure of the class grows rapidly.
2. Use Bridge mode
The class diagram
Abstract models
public abstract class AbstractCar{
void run(){};
}
Copy the code
Abstract road type, in this place, the most important point is that abstract road is combined with vehicle type. Bridge mode changes the inheritance relationship between the two roles into a coupling relationship, so that the two can calmly and independently change, which is also the original intention of Bridge mode.
Public abstract class AbstractRoad{AbstractCar abstracar; void run(){}; }Copy the code
This increases the client’s coupling with the road and the car. There is no need to worry about this, because the coupling is due to the creation of the object and can be resolved with the creation pattern. Combined with the creative design pattern in application to deal with specific problems.
The subclass implementation
public class Bus extends AbstractCar{ @Override void run() { // TODO Auto-generated method stub super.run(); System.out.print(" bus "); } } public class Car extends AbstractCar{ @Override void run() { super.run(); System.out.print(" car "); } } public class SpeedWay extends AbstractRoad{ @Override void run() { super.run(); aCar.run(); System.out.println(" driving on highway "); } } public class Street extends AbstractRoad{ @Override void run() { super.run(); aCar.run(); System.out.println(" driving on city streets "); }}Copy the code
Apply design patterns: Extend a dimension
Bridge mode (Bridge) to do (multidimensional variation); Combined with the above example, add a dimension of “people”, different people driving different cars on different roads (three dimensions); Combine the above to add a class “person” and call again. Code implementation:
public abstract class People { AbstractRoad abstractRoad; void run(){} } public class Man extends People{ @Override public void run() { super.run(); System.out.print(" Man open "); abstractRoad.run(); } } public class Woman extends People{ @Override public void run() { super.run(); System.out.print(" Woman open "); abstractRoad.run(); } } public static void main(String[] args){ AbstractRoad speedWay = new SpeedWay(); speedWay.aCar = new Car(); People man = new Man(); man.abstractRoad = speedWay; man.run(); AbstractRoad street = new Street(); street.aCar = new Bus(); People woman = new Woman(); woman.abstractRoad = street; woman.run(); }Copy the code
Effect and key points of implementation:
1. The Bridge pattern uses “combinatorial relationships between objects” to decouple the inherent binding between abstraction and implementation so that abstraction and implementation can vary along their respective dimensions. 2. The abstraction and implementation change along their dimensions, that is, “subclassing” them, and once you have each subclass, you can arbitrary them to get different cars on different roads. 3. Bridge mode is sometimes similar to the multi-inheritance scheme, but the multi-inheritance scheme often violates the principle of single responsibility of a class (that is, a class has only one reason for change) and has poor reusability. The Bridge pattern is a better solution than multiple inheritance. 4. The Bridge pattern is generally applied in “two very strong varying dimensions”. Sometimes even if there are two varying dimensions, the varying dimension in one direction is not drastic — in other words, the two varying dimensions will not lead to crisscross results, and the Bridge pattern is not necessary.
Applicability:
The bridge pattern should be used when: 1. If a system needs to add more flexibility between the abstract and embodied roles of the component, avoid establishing a static connection between the two levels. 2. The design requires that any changes to the implemented role should not affect the client, or that changes to the implemented role be fully transparent to the client. 3. A component has more than one abstract role and realization role, and the system needs dynamic coupling between them. 4. While there is no problem with using inheritance in a system, because abstract and embodied roles need to change independently, design requirements need to manage both independently.
Conclusion:
The Bridge pattern is a very useful and complex pattern that is well aligned with the object-oriented principles of open-close and object preference over inheritance.Copy the code