一、定义
桥接(Bridge)是用于把抽象化与实现化解耦,使得二者可以独立变化。这种类型的设计模式属于结构型模式,它通过提供抽象化和实现化之间的桥接结构,来实现二者的解耦。
二、核心
桥接模式 的核心在于 解耦抽象和实现。
注:此处的 抽象 并不是指 抽象类 或 接口 这种高层概念,实现 也不是 继承 或 接口实现 。抽象 与 实现 其实指的是两种独立变化的维度。其中,抽象 包含 实现,因此,一个 抽象 类的变化可能涉及到多种维度的变化导致的。
三、优缺点
1、优点
- 抽象和实现分离:这是 桥接模式 的主要特点,也是避免使用 继承 的主要原因。使用 桥接模式,解耦了 抽象 和 实现,使得两者的变化不会对另一方产生影响,使得系统扩展性大大增强。
- 优秀的扩展能力:桥接模式 的出现就是为了解决多个独立变化的维度的耦合,其高层模块聚合关系已确定(稳定)。因此,无论是 抽象 变化还是 实现 变化,只要对其进行扩展即可,高层代码无需任何更改即可接收扩展。高层代码依赖抽象,严格遵循了 依赖倒置原则。
- 实现细节对客户透明:由于 桥接模式 在高层模块(抽象层)通过聚合关系构建了稳定的架构(封装)。因此,客户只需与高层模块交互,对 抽象 和 实现 的细节完全不需关注。
2、缺点
- 桥接模式 由于聚合关联关系建立在抽象层,要求开发者针对抽象进行设计与编程,因此会增加系统的理解与设计难度。
四、主要解决
当一个类内部具备两种或多种变化维度时,使用 桥接模式 可以解耦这些变化的维度,使高层代码架构稳定
对于那些不希望使用继承或因为多层次继承导致系统类的个数急剧增加的系统,桥接模式尤为适用。
五、角色
• Abstraction:抽象类
• RefinedAbstraction:扩充抽象类
• Implementor:实现类接口
• ConcreteImplementor:具体实现类
六、代码结构
class Client {
public static void main(String[] args) {
// 来一个实现化角色
IImplementor imp = new ConcreteImplementor();
// 来一个抽象化角色,聚合实现
Abstraction abs = new RefinedAbstraction(imp);
// 执行操作
abs.operation();
}
// 实现类接口
interface IImplementor {
void operationImpl();
}
// 具体实现类
static class ConcreteImplementor implements IImplementor {
@Override
public void operationImpl() {
System.out.println("I'm ConcreteImplementor A");
}
}
// 抽象类
abstract static class Abstraction {
protected IImplementor mImplementor;
public Abstraction(IImplementor implementor) {
this.mImplementor = implementor;
}
public void operation() {
this.mImplementor.operationImpl();
}
}
// 扩充抽象类
static class RefinedAbstraction extends Abstraction {
public RefinedAbstraction(IImplementor implementor) {
super(implementor);
}
@Override
public void operation() {
super.operation();
System.out.println("refined operation");
}
}
}
七、代码问题引入
一个汽车大型商场要卖车,按动力类型可分为新能源的和传统汽车,按品牌又可分为思域,吉利等,我们现在要实现分类销售,应该如何实现呢?如果动力类型分为3种,品牌有很多种,那么又该如何实现呢?
八、传统继承方法案例
按照传统继承的方法来分类,我们有一个总接口为car,下面有两个实现类分别为newCar,olderCar,newCar下又有两个子类newjjilicar,newsiyucar,oldercar下也有两个子类olderjilicar,oldersiyucar
代码实现如下
public interface Car {
//卖车
void saleCar();
}
public class NewCar implements Car{
@Override
public void saleCar() {
System.out.println("卖出一辆新能源汽车");
}
}
public class OlderCar implements Car{
@Override
public void saleCar() {
System.out.println("卖出一辆传统汽车");
}
}
public class NewJIliCar extends NewCar{
@Override
public void saleCar(){
System.out.println("卖出一辆吉利新能源汽车");
}
}
public class NewSiyuCar extends NewCar {
@Override
public void saleCar(){
System.out.println("卖出一辆思域系能源汽车");
}
}
public class OlderJiliCar extends OlderCar {
@Override
public void saleCar(){
System.out.println("卖出一辆吉利传统能源汽车");
}
}
public class OlderSiyuCar extends OlderCar {
@Override
public void saleCar(){
System.out.println("卖出一辆思域传统能源汽车");
}
}
两个种类,两个品牌的时候按照继承的方式还可以实现,可是当加一个动力类型时,按照继承的方式又需要添加一个实现类,两个实现子类,如果我需要再加个品牌,我原来的种类下的品牌车也需要加上新加的品牌
从上面的图来看,这是我们用继承的方式扩展起来就极其不方便,所以接下来我们用桥接模式编写代码。
九、桥接模式代码案例
仔细分析上面的示例,根据示例的功能要求,示例的变化具有两个纬度,一个纬度是抽象的车的动力类型,包括新能源,传统动力,混合动力;另一个纬度在车具体的品牌商,包括思域,吉利,大众。这两个纬度一共可以组合出9种不同的可能性来,它们的关系如下图所示:
Abstraction:抽象类
package bridge.v2;
/**
* @Package: bridge.v2
* @ClassName: CarTypeAbstraction
* @Author: tanp
* @Description: 抽象类 汽车品牌类型的抽象类
* @Date: 2020/11/4 15:22
*/
public abstract class CarTypeAbstraction {
CarPowerIImplementor carPowerIImplementor;
public CarTypeAbstraction(CarPowerIImplementor carPowerIImplementor){
this.carPowerIImplementor = carPowerIImplementor;
}
public void sale(String type){
carPowerIImplementor.saleCar(type);
}
}
RefinedAbstraction:扩充抽象类
package bridge.v2;
/**
* @Package: bridge.v2
* @ClassName: JiliCar
* @Author: tanp
* @Description: 扩充抽象类,吉利牌汽车
* @Date: 2020/11/4 15:26
*/
public class JiliCar extends CarTypeAbstraction{
public JiliCar(CarPowerIImplementor carPowerIImplementor) {
super(carPowerIImplementor);
}
@Override
public void sale(String type){
super.sale(type);
}
}
package bridge.v2;
/**
* @Package: bridge.v2
* @ClassName: SiyuCar
* @Author: tanp
* @Description: 扩充抽象类,思域牌汽车
* @Date: 2020/11/4 15:32
*/
public class SiyuCar extends CarTypeAbstraction{
public SiyuCar(CarPowerIImplementor carPowerIImplementor) {
super(carPowerIImplementor);
}
@Override
public void sale(String type){
super.sale(type);
}
}
package bridge.v2;
/**
* @Package: bridge.v2
* @ClassName: DazhongCar
* @Author: tanp
* @Description: 扩充抽象类,大众牌汽车
* @Date: 2020/11/4 15:40
*/
public class DazhongCar extends CarTypeAbstraction{
public DazhongCar(CarPowerIImplementor carPowerIImplementor) {
super(carPowerIImplementor);
}
@Override
public void sale(String type){
super.sale(type);
}
}
Implementor:实现类接口
package bridge.v2;
/**
* @Package: bridge.v2
* @ClassName: CarBrandIImplementor
* @Author: tanp
* @Description: 实现类接口:汽车动力类型接口
* @Date: 2020/11/4 15:19
*/
public interface CarPowerIImplementor {
public void saleCar(String type);
}
ConcreteImplementor:具体实现类
package bridge.v2;
/**
* @Package: bridge.v2
* @ClassName: NewCar
* @Author: tanp
* @Description: 具体实现类,新能源汽车
* @Date: 2020/11/4 15:36
*/
public class NewCar implements CarPowerIImplementor{
@Override
public void saleCar(String type) {
System.out.println("卖出一辆新能源"+type+"汽车");
}
}
package bridge.v2;
/**
* @Package: bridge.v2
* @ClassName: OlderCar
* @Author: tanp
* @Description: 具体实现类,传统能源汽车
* @Date: 2020/11/4 15:38
*/
public class OlderCar implements CarPowerIImplementor{
@Override
public void saleCar(String type) {
System.out.println("卖出一辆传统能源"+type+"汽车");
}
}
package bridge.v2;
/**
* @Package: bridge.v2
* @ClassName: HunheCar
* @Author: tanp
* @Description: 具体实现类,混合能源汽车
* @Date: 2020/11/4 15:39
*/
public class HunheCar implements CarPowerIImplementor{
@Override
public void saleCar(String type) {
System.out.println("卖出一辆混合能源"+type+"汽车");
}
}
main
package bridge.v2;
/**
* @Package: bridge.v2
* @ClassName: DemoClient
* @Author: tanp
* @Description: ${description}
* @Date: 2020/11/4 15:46
*/
public class DemoClient {
public static void main(String[] args) {
//创建具体的实现对象,新能源汽车
CarPowerIImplementor carPowerIImplementor = new NewCar();
//创建一个扩充类对象,吉利汽车
CarTypeAbstraction carTypeAbstraction = new JiliCar(carPowerIImplementor);
carTypeAbstraction.sale("吉利");
//创建一个扩充类对象,思域汽车
carTypeAbstraction = new SiyuCar(carPowerIImplementor);
carTypeAbstraction.sale("思域");
carTypeAbstraction = new DazhongCar(carPowerIImplementor);
carTypeAbstraction.sale("大众");
//创建具体的实现对象,传统能源汽车
carPowerIImplementor = new OlderCar();
//创建一个扩充类对象,吉利汽车
carTypeAbstraction = new JiliCar(carPowerIImplementor);
carTypeAbstraction.sale("吉利");
//创建一个扩充类对象,思域汽车
carTypeAbstraction = new SiyuCar(carPowerIImplementor);
carTypeAbstraction.sale("思域");
carTypeAbstraction = new DazhongCar(carPowerIImplementor);
carTypeAbstraction.sale("大众");
//创建具体的实现对象,混合能源汽车
carPowerIImplementor = new HunheCar();
//创建一个扩充类对象,吉利汽车
carTypeAbstraction = new JiliCar(carPowerIImplementor);
carTypeAbstraction.sale("吉利");
//创建一个扩充类对象,思域汽车
carTypeAbstraction = new SiyuCar(carPowerIImplementor);
carTypeAbstraction.sale("思域");
carTypeAbstraction = new DazhongCar(carPowerIImplementor);
carTypeAbstraction.sale("大众");
}
}
经过桥接模式的编码方式后,我们发现当我们需要新增一个品牌,或者一个动力类型时,我们只需新增一个类即可,而不需要像之前继承的方法,新增很多个类。而且我们新增品牌和新增种类两者完全隔离,没有任何耦合。