介绍
哈哈,Bridge和我的昵称差不多!
桥接模式其实很简单的,网上很多学习资料大概是为了介绍合成/聚合复用原则或者是为了说清楚桥接模式的好处,都会先用一个特别复杂的错误案例,然后将学习的同学脑袋弄晕,然后才开始介绍桥接模式。
那么,今天我就直接说举例说桥接模式,然后再举错误的例子,最后介绍合成/聚合原则
案例分析
假设我们希望分别从“用途”和“品牌”2个方面去创建汽车,比如:
- 用途(Purpose): 家用、赛道、商务……
- 品牌(Brand):特斯拉、宝马、BYD……
如果是桥接模式,创建方式如下:
桥接模式UML
桥接模式代码
- 模拟品牌的4个类
package com.bridge.bridge;
public abstract class Brand {
protected Purpose purpose;
public abstract void show();
}
class BMW extends Brand {
protected String name = "宝马";
public BMW(Purpose purpose){
this.purpose = purpose;
}
public void show(){
System.out.println("这是一辆" + purpose.name() + "的" + this.name);
}
}
class BYD extends Brand {
protected String name = "比亚迪";
public BYD(Purpose purpose){
this.purpose = purpose;
}
public void show(){
System.out.println("这是一辆" + purpose.name() + "的" + this.name);
}
}
class Tesla extends Brand {
protected String name = "特斯拉";
public Tesla(Purpose purpose){
this.purpose = purpose;
}
public void show(){
System.out.println("这是一辆" + purpose.name() + "的" + this.name);
}
}
- 模拟用途的4个类
public abstract class Purpose {
public abstract String name();
}
class Family extends Purpose{
@Override
public String name() {
return "家用";
}
}
class Sport extends Purpose{
@Override
public String name() {
return "运动型";
}
}
class Business extends Purpose{
@Override
public String name() {
return "商务";
}
}
- 调用方式和打印结果
public class Demo {
public static void main(String[] args) {
Purpose purpose = new Sport();
Brand brand = new Tesla(purpose);
brand.show();
purpose = new Business();
brand = new BMW(purpose);
brand.show();
}
}
这是一辆运动型的特斯拉
这是一辆商务的宝马
怎么样,是不是感觉很简单,好像并没有什么问题啊?为什么网上好多教程会将桥接模式说的那么复杂呢?那是因为有点设计模式基础或者刚学会继承的同学很容易出现下面的设计错误!
错误的设计
- 一对比就知道,下面的设计非常麻烦,如果此时品牌增加本田,使用类型增加越野,那么设计图将变得非常庞大,而难以维护。
- 当然先按照用途进行分类也会出现同样的问题。
- 出现这样的问题,就是因为不知道合成/聚合复用原则(CARP)
合成/聚合复用原则
在第一篇设计模式中,我就提到过/聚合复用原则:
- 程序中,如果都使用继承的方式扩展类,那么类将会变得非常大,而难以维护
- 所以,我们应该尽量使用合成、聚合的方式去替代类的继承
- 合成、聚合的方式也提高的类的利用率
- 聚合表示一种弱的‘拥有’关系,体现的是A对象可以包含B对象,但B对象不是A对象的一部分
- 合成则是一种强的“拥有”关系,体现了严格的部分和整体的关系,部分和整体的生命周期一样
总结
在开发中或许不知不觉就在使用设计模式了,因为我们深入的理解了设计的原则,就比如今天的桥接模式。
桥接模式其实就是将一个拥有多个职责的类,从不同的维度进行独立拆分出来,减少了这些职责的耦合而已。(将抽象部分与它的实现部分分离,使它们都可以独立地变化)