共计 3416 个字符,预计需要花费 9 分钟才能阅读完成。
一、桥接模式介绍
1. 解决的问题
次要解决在有多种可能变动的状况下,用继承会造成类爆炸的问题,扩大起来不灵便。
2. 定义
桥接模式是一种结构型设计模式,能够将一个大类或一系列严密相干的类拆分为形象和实现两个独立的档次架构,从而在开发时别离应用。
简略来说,就是通过讲形象局部和实现局部拆散,把多种可匹配的应用进行组合。外围实现是在 A 类蕴含 B 类接口,通过构造函数实现 B 类的传递,这个 B 类就是设计的 桥。
3. 利用场景
- 拆分或重组一个具备多重性能的庞杂类(比方能与多个数据库服务器进行交互的类)。
- 心愿在几个独立维度上扩大一个类。
即每个维度抽取独立的类档次,初始类将相干工作委派给所属对应类档次的对象,无需本人实现所有工作。
- 在运行时须要切换不同的实现办法。
这种水平上与策略模式很类似,因为都基于 组合模式——行将工作委派给其余对象。
但实际上,桥接模式不仅定义了实现局部的接口,也定义了形象局部的接口,形象局部和实现局部都是可可扩大的,两者能够一直组合成各种模式的构造,这也体现了构造模式的特点:通过继承、聚合的形式组合类和对象已造成更大的构造。
而策略模式关注点在于策略接口的各种实现,只是为调用策略模式的上下文提供了一种合作,不波及两者构造的互为组合,所以它是行为模式的一种。行为模式的次要特点就是解决对象之间的通信形式,往往是通过中介者对象将通信单方解耦,而策略模式就是将上下文和理论的算法提供解耦。
因而桥接模式与策略模式相比,构造更为简单,表白的内容更多。桥接模式次要表白的是将实质是两个并不内聚的体系区别开来,使得它们能够涣散的组合。能够认为桥接中必然存在着策略模式。
二、桥接模式优缺点
1. 长处
- 能够创立与平台无关的类和程序。
- 客户端代码仅与高层形象局部进行交互,不会接触到平台的详细信息。
- 开闭准则:能够新增形象局部和实现局部,且它们之间不会相互影响。
- 繁多职责准则:形象局部专一于解决高层逻辑,实现局部解决平台细节。
2. 毛病
- 对于高内聚的类,应用该模式可能让代码更加简单。
三、桥接模式利用实例:第三方登录
1. 实例场景
上线一个新产品,为了缩小本地注册的繁琐而带来的隐形用户散失,进步注册转化率,通常须要反对第三方登录,这样也能够通过受权获取用户在第三方平台的社交信息,能够后续针对用户的社交关系网剖析用户属性,从而进行有目的性的营销宣传。
接下来就以反对第三方登录作为模仿场景。
2. 桥接模式实现
2.1 工程构造
bridge-pattern
└─ src
├─ main
│ └─ java
│ └─ org.design.pattern.bridge
│ ├─ model
│ │ ├─ LoginApi.java
│ │ ├─ WxApi.java
│ │ └─ QqApi.java
│ └─ service
│ ├─ LoginService.java
│ └─ impl
│ └─ LoginServiceImpl.java
└─ test
└─ java
└─ org.design.pattern.bridge.test
└─ LoginServiceTest.java
2.2 代码实现
2.2.1 第三方 Api
登录接口
/**
* 登录 Api
*/
public interface LoginApi {boolean login();
}
微信 Api
/**
* 微信 Api
*/
public class WxApi implements LoginApi {private final Logger log = LoggerFactory.getLogger(LoginApi.class);
private String $loginApi;
private String $apiKey;
public WxApi(String $loginApi, String $apiKey) {
this.$loginApi = $loginApi;
this.$apiKey = $apiKey;
}
@Override
public boolean login() {log.info("微信登录胜利");
return true;
}
}
QQ Api
/**
* QQApi
*/
public class QqApi implements LoginApi {private final Logger log = LoggerFactory.getLogger(LoginApi.class);
private String $loginApi;
private String $apiKey;
public QqApi(String $loginApi, String $apiKey) {
this.$loginApi = $loginApi;
this.$apiKey = $apiKey;
}
@Override
public boolean login() {log.info("QQ 登录胜利");
return true;
}
}
2.2.2 登录服务
登录服务
/**
* 登录服务
*/
public abstract class LoginService {protected final Logger log = LoggerFactory.getLogger(LoginService.class);
protected LoginApi loginApi;
public LoginService(LoginApi loginApi) {this.loginApi = loginApi;}
public abstract boolean login();}
登录服务实现
/**
* 登录服务实现类
*/
public class LoginServiceImpl extends LoginService {public LoginServiceImpl(LoginApi loginApi) {super(loginApi);
}
@Override
public boolean login() {return this.loginApi.login();
}
}
2.3 测试验证
2.3.1 测试验证类
public class LoginServiceTest {
@Test
public void testLogin() {
// 微信登录
LoginApi wxApi = new WxApi("https://mp.weixin.qq.com", "xxx");
LoginService wxLoginService = new LoginServiceImpl(wxApi);
wxLoginService.login();
//QQ 登录
LoginApi qqApi = new QqApi("https://www.qq.com", "xxx");
LoginService qqLoginService = new LoginServiceImpl(qqApi);
qqLoginService.login();}
}
2.3.2 测试后果
15:44:28.993 [main] INFO o.d.pattern.bridge.model.LoginApi - 微信登录胜利
15:44:28.996 [main] INFO o.d.pattern.bridge.model.LoginApi - QQ 登录胜利
Process finished with exit code 0
四、桥接模式构造
- 形象局部(Abstraction)提供高层管制逻辑,依赖于实现底层理论工作的理论对象。
- 实现局部(Implementation)为所有具体实现申明通用接口。形象局部仅能通过这里申明的办法与实现对象交互。
形象局部能够列出实现局部一样的办法,然而形象局部通常申明一些简单行为,这些行为依赖于多种由实现局部申明的操作。
- 具体实现(Concrete Implementations)中包含特定于平台的代码。
- 准确形象(Refined Abstraction)提供管制逻辑的变体。与其父类一样,它们通过通用实现接口与不同的实现进行交互。
- 通常状况下,客户端(Client)仅关怀如何与形象局部单干。然而,客户端须要将形象对象与一个实现对象连接起来。
设计模式并不难学,其自身就是多年教训提炼出的开发指导思想,关键在于多加练习,带着应用设计模式的思维去优化代码,就能构建出更正当的代码。
源码地址:https://github.com/yiyufxst/design-pattern-java
参考资料:
小博哥重学设计模式:https://github.com/fuzhengwei/itstack-demo-design
深刻设计模式:https://refactoringguru.cn/design-patterns/catalog