桥接模式

119 阅读5分钟

桥接模式

介绍

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第2天

🍐桥接模式是一种结构模式,用于将抽象与其实现解耦,以便两者可以独立变化。 🍐桥接模式通过在抽象类和实现类之间提供桥接结构来解耦抽象类和它的实现类。利用封装、聚合和继承来将责任分离到不同的类中 🍐桥接模式可以让我们避免抽象与其实现之间的编译时绑定,这样可以在程序运行时选择具体实现。

实现

👉案例: 假设有一家公司生产各种类型的车辆,如自行车、汽车和公共汽车。由于可以引入新的自行车和汽车模型,并且有不同的制造工艺,因此车辆经常发生变化。未来可能还会有其他新的车辆,如小型摩托车或卡车。

所有车辆都在车间被制造、装配、质检。下面是交通工具类Vehicle

/**
 * 交通工具类
 *
 * @author hz
 * @since 2022/10/11
 */
public abstract class Vehicle {
​
    /**
     * 车间的装配线
     */
    protected List<WorkShop> workshops = new ArrayList<>();
​
    protected Vehicle() {
        super();
    }
​
    /**
     * 添加车间
     *
     * @param workshop 车间
     * @return 是否添加成功
     */
    public boolean joinWorkshop(WorkShop workshop) {
        return workshops.add(workshop);
    }
​
    /**
     * 制造交通工具
     */
    public abstract void manufacture();
​
    /**
     * 制造花费的时间
     *
     * @return 时间
     */
    public abstract int minWorkTime();
​
}
​

下面是自行车🚲Bike

public class Bike extends Vehicle {
​
    @Override
    public void manufacture() {
        System.out.println("制造自行车");
        workshops.forEach(workshop -> workshop.work(this));
        System.out.println("制造完成");
        System.out.println();
    }
​
    @Override
    public int minWorkTime() {
        return 5;
    }
​
}
​

下面是汽车🚗Car

public class Car extends Vehicle {
​
    @Override
    public void manufacture() {
        System.out.println("制造汽车");
        workshops.stream().forEach(workshop -> workshop.work(this));
        System.out.println("制作完成");
        System.out.println();
    }
​
    @Override
    public int minWorkTime() {
        return 10;
    }
​
}

下面是🚌Bus

public class Bus extends Vehicle {
​
    @Override
    public void manufacture() {
        System.out.println("制造巴士");
        workshops.stream().forEach(workshop -> workshop.work(this));
        System.out.println("制造完成");
        System.out.println();
    }
​
    @Override
    public int minWorkTime() {
        return 20;
    }
​
}

定义了车辆类型后,我们没有实现具体的制造类,如ProduceBikeAssembleBikeProduceCarAssembleCar。 现在创建接口WorkShop,让每辆车都加入车间执行其制造或维修过程。它将充当车辆类型和具体车间(实现者)之间的桥梁,并使用work()方法执行制造工作。 下面是代码WorkShop:

/**
 * 车间
 *
 * @author hz
 * @since 2022/10/11
 */
public abstract class WorkShop {
​
    /**
     * 车辆制造方法
     *
     * @param vehicle 要制造的交通工具
     */
    public abstract void work(Vehicle vehicle);
​
}

WorkShop充当各种类型车辆及其制造工作(实施者)之间的桥梁。现在,我们需要创建WorkShop的实施者,以定义执行制造工作所需的各种类型的车间。 以下是ProduceWorkShop类的代码:

/**
 * 生产车间
 *
 * @author hz
 * @since 2022/10/11
 */
public class ProduceWorkShop extends WorkShop {
​
    public ProduceWorkShop() {
        super();
    }
​
    @Override
    public void work(Vehicle vehicle) {
        System.out.print("生产中... ");
        long timeToTake = 300L * vehicle.minWorkTime();
        try {
            TimeUnit.MILLISECONDS.sleep(timeToTake);
        } catch (InterruptedException exp) {
            // nothing to do for now.
        }
        System.out.printf("(Time taken: %d millis), Done.\n", timeToTake);
    }
​
}

下面是AssembleWorkShop代码

/**
 * 装配车间
 *
 * @author hz
 * @since 2022/10/11
 */
public class AssembleWorkShop extends WorkShop {
​
    public AssembleWorkShop() {
        super();
    }
​
    @Override
    public void work(Vehicle vehicle) {
        System.out.print("装配中... ");
        long timeToTake = 200L * vehicle.minWorkTime();
        try {
            TimeUnit.MILLISECONDS.sleep(timeToTake);
        } catch (InterruptedException exp) {
            // nothing to do for now.
        }
        System.out.printf("(Time taken: %d millis), Done.\n", timeToTake);
    }
​
}
​

下面是PaintWorkShop代码

/**
 * 油漆车间
 *
 * @author hz
 * @since 2022/10/11
 */
public class PaintWorkShop extends WorkShop {
​
    public PaintWorkShop() {
        super();
    }
​
    @Override
    public void work(Vehicle vehicle) {
        System.out.print("喷漆中... ");
        long timeToTake = 100 * vehicle.minWorkTime();
        try {
            TimeUnit.MILLISECONDS.sleep(timeToTake);
        } catch (InterruptedException exp) {
            // nothing to do for now.
        }
        System.out.printf("(Time taken: %d millis), Done.\n", timeToTake);
    }
​
}
​

下面是RepairWorkShop代码

/**
 * 维修车间
 *
 * @author hz
 * @since 2022/10/11
 */
public class RepairWorkShop extends WorkShop {

    public RepairWorkShop() {
        super();
    }

    @Override
    public void work(Vehicle vehicle) {
        System.out.print("维修中... ");
        long timeToTake = 150L * vehicle.minWorkTime();
        try {
            TimeUnit.MILLISECONDS.sleep(timeToTake);
        } catch (InterruptedException exp) {
            // nothing to do for now.
        }
        System.out.printf("(Time taken: %d millis), Done.\n", timeToTake);
    }

}

下面是TestWorkShop代码

/**
 * 质检车间
 *
 * @author hz
 * @since 2022/10/11
 */
public class TestWorkShop extends WorkShop {

    public TestWorkShop() {
        super();
    }

    @Override
    public void work(Vehicle vehicle) {
        System.out.print("质检中... ");
        long timeToTake = 50L * vehicle.minWorkTime();
        try {
            TimeUnit.MILLISECONDS.sleep(timeToTake);
        } catch (InterruptedException exp) {
            // nothing to do for now.
        }
        System.out.printf("(Time taken: %d millis), Done.\n", timeToTake);
    }

}

为了让这个例子更有趣,我将定时睡眠设置为几毫秒,以表明车间在制造不同类型的车辆时花费了不同的时间。代码中有趣的部分是车辆(Bike,Car, Bus)桥接模式类型的使用,其制造实现(ProduceWorkShop,AssemableWorkShop,PaintWorkShop,TestWorkShop)通过WorkShop接口完全独立。 车辆和车间通过WorkShop Bridge接口连接,相互独立。如果需要,我们可以自由更改它们并定义新的。

现在,老baby们,一起来看看执行和测试桥接模式代码的主程序:

public class Main {

    public static void main(String[] args) {
        Vehicle bike = new Bike();
        bike.joinWorkshop(new ProduceWorkShop());
        bike.joinWorkshop(new AssembleWorkShop());
        bike.joinWorkshop(new TestWorkShop());
        bike.manufacture();

        Vehicle car = new Car();
        car.joinWorkshop(new ProduceWorkShop());
        car.joinWorkshop(new AssembleWorkShop());
        car.joinWorkshop(new PaintWorkShop());
        car.joinWorkshop(new TestWorkShop());
        car.manufacture();

        Vehicle bus = new Bus();
        bus.joinWorkshop(new RepairWorkShop());
        bus.joinWorkshop(new AssembleWorkShop());
        bus.joinWorkshop(new TestWorkShop());
        bus.manufacture();
    }

}

程序输出结果

制造自行车
生产中... (Time taken: 1500 millis), Done.
装配中... (Time taken: 1000 millis), Done.
质检中... (Time taken: 250 millis), Done.
制造完成

制造汽车
生产中... (Time taken: 3000 millis), Done.
装配中... (Time taken: 2000 millis), Done.
喷漆中... (Time taken: 1000 millis), Done.
质检中... (Time taken: 500 millis), Done.
制作完成

制造巴士
维修中... (Time taken: 3000 millis), Done.
装配中... (Time taken: 4000 millis), Done.
质检中... (Time taken: 1000 millis), Done.
制造完成


Process finished with exit code 0

总结

优点

  1. 抽象和实现的分离。
  2. 优秀的扩展能力。
  3. 实现细节对客户透明。

缺点

桥接模式的引入会增加系统的理解与设计难度,由于聚合关联关系建立在抽象层,要求开发者针对抽象进行设计与编程。

使用场景

  • 一个类存在两个独立变化的维度,且这两个维度都需要进行扩展。
  • 希望避免抽象与其实现之间的永久绑定。例如,在程序运行时可选择或切换不同的实现。
  • 抽象及其实现都应该通过子类化进行扩展。在这种情况下,桥接模式可以组合不同的抽象和实现,并独立扩展它们。
  • 抽象实现中的更改不应对客户端产生影响;也就是说,他们的代码不必重新编译。