该项目源码地址:https://github.com/lastwhispers/code/tree/master/java-basic/design-pattern
(设计模式相关代码与笔记)
1. 定义
将抽象部分与它的具体实现部分分离。使它们都可以独立地变化。通过组合的方式建立两个类之间联系,而不是继承。
2. 适用情况
- 抽象和具体实现之间增加更多的灵活性
- 一个类存在两个(或多个)独立变化的维度。且这两个(或多个)维度都需要独立进行扩展
- 不希望使用继承,或因为多层继承导致系统类的个数剧增
3. 类图与角色
桥接模式类图- Abstraction为抽象化角色,定义出该角色的行为,同时保存一个对实现化角色的引用;
- Implementor是实现化角色,它是接口或者抽象类,定义角色必需的行为和属性;
- RefinedAbstraction为修正抽象化角色,引用实现化角色对抽象化角色进行修正;
- ConcreteImplementor为具体实现化角色,实现接口或抽象类定义的方法或属性。
4. 相关设计模式
桥接模式和组合模式
- 组合模式强调的是部分和整体间的组合,桥接模式强调的是平行级别上,不同类的组合
桥接模式和适配器模式
- 适配器模式改变已有的接口,桥接模式分离抽象和具体。
5. 模式实例
背景:中国有很多银行,有中国农业银行和中国工商银行关于我们的账号,有定期账号和活期账号。
(1)桥接模式-实现
有一个账户接口:
public interface Account {
/** 打开我们的账号,打开账号,就要返回账号 */
Account openAccount();
/** 打开我们的账号,查看为什么账户类型,是定期类型还是活期类型 */
void showAccountType();
}
一个定期的账号:
/** 定期的账号 */
public class DepositAccount implements Account {
@Override
public Account openAccount() {
System.out.println("定期账号");
return new DepositAccount();
}
@Override
public void showAccountType() {
System.out.println("这是一个定期账号");
}
}
一个活期的账号:
/** 活期账号 */
public class SavingAccount implements Account {
@Override
public Account openAccount() {
System.out.println("打开活期账号");
return new SavingAccount();
}
@Override
public void showAccountType() {
System.out.println("这是一个活期账号");
}
}
(2)桥接模式-抽象
将Account账户接口组合到这个银行类:
public abstract class Bank {
/** 只有子类能拿到这个Account的这个接口 */
protected Account account;
/** 组合的时候,可以通过构造器的方式来进行注入也可以通过set方法的方式来进行注入 */
public Bank(Account account) {
this.account = account;
}
/** 这里声明成和接口里面的方法名一致,只是方便理解,Bank里面的方法要委托给Account接口里面的方法 */
abstract Account openAccount();
}
我们现在看到就是Account就是具体的实现,我们要使用这个接口的具体实现。Bank是一个抽象类,然后这个抽象类里面的某个行为委托给Account的这个接口。
在前面有说到桥接模式指的就是抽象和实现分离;而这里的实现正式这里的Account的实现类。
现在这个银行接口有两个子类去继承它。
中国农业银行类:
public class ABCBank extends Bank {
/**
* 组合的时候,可以通过构造器的方式来进行注入也可以通过set方法的方式来进行注入
*
* @param account
*/
public ABCBank(Account account) {
super(account);
}
@Override
Account openAccount() {
System.out.println("打开中国农业银行账号");
//将行为委托给account
account.openAccount();
return account;
}
}
中国工商银行账号:
public class ICBCBank extends Bank {
/**
* 组合的时候,可以通过构造器的方式来进行注入也可以通过set方法的方式来进行注入
*
* @param account
*/
public ICBCBank(Account account) {
super(account);
}
@Override
Account openAccount() {
System.out.println("打开中国工商银行账号");
//将行为委托给account
account.openAccount();
return account;
}
}
(3)测试类
public class Test {
public static void main(String[]args){
Bank icbcBank = new ICBCBank(new DepositAccount());
Account icbcAccount = icbcBank.openAccount();
icbcAccount.showAccountType();
Bank icbcBank2 = new ICBCBank(new SavingAccount());
Account icbcAccount2 = icbcBank2.openAccount();
icbcAccount2.showAccountType();
Bank abcBank = new ABCBank(new SavingAccount());
Account abcAccount = abcBank.openAccount();
abcAccount.showAccountType();
}
}
测试结果:
测试结果(4)类图
将抽象与实现剥离,在Bank中使用组合引入Account,在Bank中抽象,在Acount中实现。将需要的功能委托给实现。
类图6. 优缺点
优点:
- 分离抽象部分及其具体实现部分
- 提高了系统的可扩展性
- 符合开闭原则
- 符合合成复用原则
缺点:
- 增加了系统的理解与设计难度
- 需要正确地识别出系统中两个独立变化的维度
7. 扩展-JDK1.7以及框架源码中的桥接模式
7.1 java.sql.Driver、java.sql.DriverManager与java.sql.DriverInfo
mysql的Driver、oracle的Driver就是桥接模式的实现部分。
7.2 DriverManager与DriverInfo(也就是Driver)实现了桥接模式
网友评论