设计模式 -- Bridge(桥模式)
桥模式(Bridge)
由于某些类型的固有的实现逻辑,使得它们具有两个变化的维度,乃至多个维度的变化
如何应对这种多维度的变化?如何利用面向对象技术来使得类型可以轻松地沿着两个乃至多个方向变化、而不引入额外的复杂度
原先
假设有如下的通信的伪码描述包括登陆、发信息、播放音乐等等的功能,同时也支持不同的平台的支持,比如PC、移动端等,其中版本也具有不同的功能,比如精简版和完整版。
// 通信接口类
interface Messager {
// 登录
void Login(String username, String password);
// 发送消息
void SendMessage(String message);
// 发送图片
void SendPicture();
// 播放声音
void PlaySound();
// 绘制形状
void DrawShape();
// 输出信息
void WriteText();
// 连接
void Connect();
};
// PC平台实现
abstract class PCMessagerBase implements Messager{
public void PlaySound(){
//**********
}
public void DrawShape(){
//**********
}
public void WriteText(){
//**********
}
public void Connect(){
//**********
}
};
// 移动平台实现
abstract class MobileMessagerBase implements Messager{
public void PlaySound(){
//==========
}
public void DrawShape(){
//==========
}
public void WriteText(){
//==========
}
public void Connect(){
//==========
}
};
// PC具体业务、精简版
class PCMessagerLite extends PCMessagerBase{
@Override
public void Login(String username, String password) {
// .........
Connect();
}
@Override
public void SendMessage(String message) {
// .........
WriteText();
}
@Override
public void SendPicture() {
// .........
DrawShape();
}
};
// PC具体业务、完整版
class PCMessagerPerfect extends PCMessagerLite{
@Override
public void Login(String username, String password) {
PlaySound();
super.Login(username, password);
// .........
}
@Override
public void SendMessage(String message) {
PlaySound();
super.SendMessage(message);
// .........
}
@Override
public void SendPicture() {
PlaySound();
super.SendPicture();
// .........
}
};
// 移动端具体业务、精简版
class MobileMessagerLite extends MobileMessagerBase{
@Override
public void Login(String username, String password) {
// .........
Connect();
}
@Override
public void SendMessage(String message) {
// .........
WriteText();
}
@Override
public void SendPicture() {
// .........
DrawShape();
}
};
// 移动端具体业务、完整版
class MobileMessagerPerfect extends MobileMessagerLite{
@Override
public void Login(String username, String password) {
PlaySound();
super.Login(username, password);
// .........
}
@Override
public void SendMessage(String message) {
PlaySound();
super.SendMessage(message);
// .........
}
@Override
public void SendPicture() {
PlaySound();
super.SendPicture();
// .........
}
}
上面的代码通过观察发现pc业务和移动端业务调用的方法是固定的、即稳定的、完成能换成调用接口、这样只需将PCMessagerBase和MobileMessagerBase抽出一个共性的类、然后pc和移动的完整业务假定是一样的、这样也可封装成一个类
重构
// 通信接口类
abstract class Messager {
protected MessagerImpl messagerImpl;
Messager(MessagerImpl messagerImpl) {
this.messagerImpl = messagerImpl;
}
// 登录
abstract void Login(String username, String password);
// 发送消息
abstract void SendMessage(String message);
// 发送图片
abstract void SendPicture();
};
// 通信接口类
interface MessagerImpl {
// 播放声音
void PlaySound();
// 绘制形状
void DrawShape();
// 输出信息
void WriteText();
// 连接
void Connect();
}
// PC平台实现
class PCMessagerBase implements MessagerImpl{
public void PlaySound(){
//**********
}
public void DrawShape(){
//**********
}
public void WriteText(){
//**********
}
public void Connect(){
//**********
}
};
// 移动平台实现
class MobileMessagerBase implements MessagerImpl{
public void PlaySound(){
//==========
}
public void DrawShape(){
//==========
}
public void WriteText(){
//==========
}
public void Connect(){
//==========
}
};
// 具体业务、精简版
class MessagerLite extends Messager {
MessagerLite(MessagerImpl messagerImpl) {
super(messagerImpl);
}
@Override
public void Login(String username, String password) {
messagerImpl.Connect();
// .........
}
@Override
public void SendMessage(String message) {
messagerImpl.WriteText();
// .........
}
@Override
public void SendPicture() {
messagerImpl.DrawShape();
// .........
}
};
// 具体业务、完整版
class MessagerPerfect extends Messager {
MessagerPerfect(MessagerImpl messagerImpl) {
super(messagerImpl);
}
@Override
public void Login(String username, String password) {
messagerImpl.PlaySound();
// .........
messagerImpl.Connect();
// .........
}
@Override
public void SendMessage(String message) {
messagerImpl.PlaySound();
// .........
messagerImpl.WriteText();
// .........
}
@Override
public void SendPicture() {
messagerImpl.PlaySound();
// .........
messagerImpl.DrawShape();
// .........
}
}
public class Main {
@Test
public void T1() {
final MessagerImpl messagerImpl = new PCMessagerBase();
final MessagerPerfect messagerPerfect = new MessagerPerfect(messagerImpl);
}
}
要点总结
- Bridge模式使用“对象间的组合关系”解耦了抽象和实现之间固有的绑定关系,使得抽象和实现可以沿着各自的维度来变化。所谓抽象和实现沿着各自维度的变化,即“子类化”他们。
- Bridge模式有时候类似于多继承方案,但是多继承方案往往违背单一指责原则(即一个类只有一个变化的原因),复用性较差。Bridge模式是比多继承方案更好的解决方法。
- Bridge模式的应用一般在“两个非常强的变化维度”,有时一个类也有多于两个的变化维度,这是可以使用Bridge的扩展模式。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)