一、介绍
桥接模式是将实现与抽象放在两个不同的类层次中,是两个层次可以独立改变,属于结构性模式,它是基于类的最小设计原则,通过使用封装,聚合及继承等行为,让不同的类承担不同的职责。主要特点是把抽象与具体行为实现分离开来,从而可以保持各部分的独立性以及应对他们的功能扩展。
二、需求说明
需求:对不同的电脑类型的不同品牌实现具体操作,比如有开机、关机、打游戏等操作。看上面的需求说明图,第一反应就是按部就班的按照传统的方式实现,类图就跟上面的需求说明图大同小异。但是传统的方式存在很多问题。
传统方式解决存在的问题:
- 扩展性问题:扩展性问题俗称类爆炸,如果我们再增加一种电脑的形态(笔记本),就需要增加各个品牌电脑的类,同样如果我们增加一个电脑品牌,也需要在各个电脑形态类下增加相应的品牌。
- 违反单一职责原则:当我们增加电脑形态时,需要增加所有品牌的电脑,必然增加代码的维护成本。
三、案例
- 电脑品牌接口
/**
* 电脑品牌能力接口
*
* @author zhangxs
**/
public interface ComputerBrand {
/** 开机 */
void open();
/** 关机 */
void close();
/** 打游戏 */
void game();
}
- 电脑形态抽象类
/**
* 电脑形态 (台式机、笔记本、一体机)
*
* @author zhangxs
**/
public abstract class ComputerType {
/** 桥接模式的灵魂:组合 */
protected ComputerBrand computerBrand;
public ComputerType(ComputerBrand computerBrand) {
this.computerBrand = computerBrand;
}
protected void open() {
this.computerBrand.open();
}
protected void close() {
this.computerBrand.close();
}
protected void game() {
this.computerBrand.game();
}
}
- 台式机
/**
* 台式机
*
* @author zhangxs
**/
public class DesktopComputer extends ComputerType{
public DesktopComputer(ComputerBrand computerBrand) {
super(computerBrand);
}
@Override
public void open() {
super.open();
System.out.println("台式电脑");
}
@Override
public void close() {
super.close();
System.out.println("台式电脑");
}
@Override
public void game() {
super.game();
System.out.println("台式电脑");
}
}
- 笔记本
/**
* 笔记本
*
* @author zhangxs
**/
public class NotebookComputer extends ComputerType {
public NotebookComputer(ComputerBrand computerBrand) {
super(computerBrand);
}
@Override
public void open() {
super.open();
System.out.println("笔记本电脑");
}
@Override
public void close() {
super.close();
System.out.println("笔记本电脑");
}
@Override
public void game() {
super.game();
System.out.println("笔记本电脑");
}
}
- 一体机
/**
* 一体机
*
* @author zhangxs
**/
public class IntegrationComputer extends ComputerType {
public IntegrationComputer(ComputerBrand computerBrand) {
super(computerBrand);
}
@Override
public void open() {
super.open();
System.out.println("一体式电脑");
}
@Override
public void close() {
super.close();
System.out.println("一体式电脑");
}
@Override
public void game() {
super.game();
System.out.println("一体式电脑");
}
}
- 联想
/**
* 联想
*
* @author zhangxs
**/
public class Lenovo implements ComputerBrand {
@Override
public void open() {
System.out.println("联想开机");
}
@Override
public void close() {
System.out.println("联想关机");
}
@Override
public void game() {
System.out.println("联想打游戏");
}
}
- 华硕
/**
* 华硕
*
* @author zhangxs
**/
public class Asus implements ComputerBrand {
@Override
public void open() {
System.out.println("华硕开机");
}
@Override
public void close() {
System.out.println("华硕关机");
}
@Override
public void game() {
System.out.println("华硕打游戏");
}
}
- 戴尔
/**
* 戴尔
*
* @author zhangxs
**/
public class Dell implements ComputerBrand {
@Override
public void open() {
System.out.println("戴尔开机");
}
@Override
public void close() {
System.out.println("戴尔关机");
}
@Override
public void game() {
System.out.println("戴尔打游戏");
}
}
- 测试
/**
* 测试
*
* @author zhangxs
**/
public class Test {
public static void main(String[] args) {
// 华硕台式
DesktopComputer asusDesktop = new DesktopComputer(new Asus());
asusDesktop.open();
asusDesktop.game();
asusDesktop.close();
// 联想笔记本
NotebookComputer lenovoNotebook = new NotebookComputer(new Lenovo());
lenovoNotebook.open();
lenovoNotebook.game();
lenovoNotebook.close();
// 戴尔一体机
IntegrationComputer dellIntegration = new IntegrationComputer(new Dell());
dellIntegration.open();
dellIntegration.game();
dellIntegration.close();
// 如果还想加一种形态,直接新建一个类,继承ComputerType类,无需其他任何修改
// 如果还想加一种品牌,直接新建一个类,实现ComputerBrand接口,无需其他任何修改
}
}
四、总结
- 桥接模式使用时的注意事项喝细节:
1、实现了抽象喝实现部分的分离,从而极大的提供了系统的灵活性,让抽象部分喝实现部分独立开来,这有助于系统进行分层设计,从而产生更好的结构化系统。
2、对于系统的高层部分,只需要知道抽象部分和实现部分的接口即可,其他部分根据具体业务完成。
3、桥接模式替代了多层继承的方案,可以减少子类的个数,降低系统的管理和维护成本。
4、桥接模式的引入增加了系统的理解和设计难度,由于聚合关联关系建立在抽象层,要求开发者针对抽象层进行设计,并面向抽象层编程。
5、桥接模式要求正确识别出系统两个独立变化的维度(抽象和实现),因此其使用范围有一定的局限性,即需要有这样的场景。
6、对于不希望使用继承或因为多层继承导致系统类的个数急剧增加的情况,比较适合使用桥接模式优化代码。 - 常见的应用场景:
1、在JDK中,JDBC驱动部分代码,就有桥接模式的影子,其中Driver接口,从桥接模式的角度来看即为抽象层接口,其下面包含了MySQL的Driver、Oracle的Driver等,这些就可以当作接口的实现类,具体的可以了解一下这部分源码
2、银行转账系统:转账通过转账方式可以分为网上转账、柜台转账、ATM转账,而转账用户类型又可以分为普通用户、银卡用户、金卡用户等等。
3、消息管理系统:消息类型可以分为即时消息、延时消息、消息来源又可以分为手机短信、邮件消息、qq消息…