设计模式GOF23-桥接模式
桥接模式(Bridge Pattern)
- 场景:商城系统中常见的商品分类,以电脑为例,如何良好的处理商品分类销售的问题?
- 解决:可以通过多层继承结构实现,关系如下图:
- 问题:
-扩展性问题(类个数膨胀)- 如果要增加一个新的电脑类型:智能手机,则要增加各个品牌下面的类;
- 如果要增加一个新的电脑品牌:苹果,则要增加各个类型下面的类。
- 违反单一职责原则
-一个类:联想笔记本,又有两个引起这个类变化的原因——品牌(联想)和类型(笔记本)
这种方式的代码就不写了,它的UML类图如下所示,是一个三层继承关系:
- 优化分析:将场景中的两个维度分开:品牌维度、类型维度,让其各自变化并不影响对方变化,而他们之间的关联关系则用“桥”来连接,如图:
核心要点
- 处理多层继承结构,处理多维度变化的场景,将各个维度设计成独立的继承结构,使各个维度可以独立的扩展在抽象层建立关系。新的类图大概如下,这样我们再左边电脑下面新增电脑类型Pad,它天然的具备品牌,在右边新加品牌,它也不影响电脑类型。
代码实现
- 实现品牌接口及两个实现类
/**
* User:tumbler
* Desc:桥接模式--品牌接口
*/
public interface Brand {
void sale();
}
/**
* Desc:桥接模式--联想
*/
class Lenovo implements Brand {
@Override
public void sale() {
System.out.println("销售联想电脑");
}
}
/**
* Desc:桥接模式--戴尔
*/
class Dell implements Brand {
@Override
public void sale() {
System.out.println("销售戴尔电脑");
}
}
- 实现电脑类型和其子类
/**
* User:tumbler
* Desc:桥接模式--电脑类型,具备品牌
*/
public class Computer {
protected Brand brand;
public Computer(Brand brand){
this.brand = brand;
}
public void sale() {
brand.sale();
}
}
/**
* 桥接模式--电脑类型,台式机
*/
class Desktop extends Computer {
public Desktop(Brand brand) {
super(brand);
}
@Override
public void sale() {
super.sale();
System.out.println("销售台式机");
}
}
/**
* 桥接模式--电脑类型,笔记本
*/
class Laptop extends Computer {
public Laptop(Brand brand) {
super(brand);
}
@Override
public void sale() {
super.sale();
System.out.println("销售笔记本");
}
}
- 客户端测试类
/**
* User:tumbler
* Desc:桥接模式--客户端测试
*/
public class Client {
public static void main(String[] args) {
Computer computer = new Laptop(new Lenovo());
computer.sale();
//结果:
//销售联想电脑
//销售笔记本
}
}
这样,我们就实现了多个维度的分离,新增一个电脑品牌,并不影响电脑类型,新增电脑类型,也不会影响电脑品牌;如果是多层继承的关系,将会有很多的类。
UML图:
开发常用应用场景
- JDBC驱动程序
- AWT中的Peer架构
- 银行日志管理
- 格式分类:操作日志,异常日志,交易日志
- 距离分类:本地日志记录,异地日志记录
- 人力资源系统中的奖金计算模块
- 奖金分类:个人奖金,团体奖金,激励奖金
- 部门分类:人事部门,研发部门,销售部门
- OA系统中的消息处理
- 业务类型:普通消息,加急消息,特急消息
- 发送方式:系统内消息,短信,邮件
总结
- 桥接模式可以取代多层继承的方案。多层继承违背了单一职责原则,复用性较差,累的个数也非常多。桥接模式可以极大的减少子类的个数,从而降低管理和维护的成本。
- 桥接模式极大的提高了系统的可扩展性,在两个变化的维度中任意扩展其中一个维度,都不需要修改原有的系统,符合开闭原则。