目录
桥接模式(Bridge Pattern)也是我们结构型设计模式的一种,桥接模式整体来说对于开发者需要深刻理解好抽象类这个概念,而且比较考验在开发前就要设计好桥接点来进行开发,所以整体的理解难度我认为是比较高,接下来我将从概念和一个示例来演示该模式。
1. 概念
桥接模式就是将抽象与实现解藕,使两者都可以独立变化。在现实生活中,某些类具有两个或多个维度的变化,如图形既可按形状分,又可按颜色分。如何设计类似于Photoshop这样的软件,能画不同形状和不同颜色的图形呢?如果用继承的方式,m种形状和n种颜色的图形就有m✖️n种,不但对应的子类很多,而且扩展极其困难。不同颜色和字体的文字、不同品牌和功率的汽车...
桥接模式将继承转为关联,降低类之间的耦合度,减少代码量。
桥接(Bridge)模式包含以下主要角色:
- 系统设计期间,如果这个类里面的一些东西,会扩展很多,这个东西就应该分离出来
- 抽象化(Abstraction)角色:定义抽象类,并包含一个对实现化对象的引用。
- 扩展抽象化(Refined Abstraction)角色:是抽象化角色的子类,实现父类中的业务方法,并通过组合关系调用实现化角色中的业务方法。
- 实现化(Implementor)角色:定义实现化角色的接口,供扩展抽象化角色调用。
2. 代码实现
这里我们举一个电商手机售卖的例子,比如说我们的电商平台需要卖手机,但是手机其实有很多品牌,每个品牌的价格都不一样;同时手机可以通过不同渠道进行贩卖,每种贩卖渠道的价钱也不一样,那么如果不进行合理的设计直接编写的话,我们可能需要实现m✖️n个类,这对于我们整个系统来说扩展性以及可读性极差,这里我们就可以进行使用桥接模式进行设计。
那么我们可以对手机这个产品进行抽象,同时我们也可以将渠道进行抽象,但是注意,不同的渠道对于一个手机来说,可能就是一个属性(这里理解可能有些困难:因为不同的渠道影响着手机的价格,那么其实是在改变手机自身的状态,所以我们可以把渠道看作手机的一个属性),这其实就是我们需要注意的,这里的渠道就是我们桥接关注点。
/**
* 1、抽象手机类
* 手机有各种销售渠道价格都不一样
*
*/
public abstract class AbstractPhone {
//桥接在此.....设计期间就得想好
//【真正会引起此类变化的一个维度直接抽取出来,通过组合的方式接起来】
//桥接+适配器 ...
AbstractSale sale; //分离渠道【桥接的关注点】
// abstract int getPrice(); 如果这么写需要多少个实现。违反开闭原则
/**
* 当前手机的描述
* @return
*/
abstract String getPhone();
public void setSale(AbstractSale sale) {
this.sale = sale;
}
}
/**
* 抽象销售渠道
* PhoneOnSale ==howToSale
* PhoneOffSale == howToSale
* PhoneStudentSale = howToSale
* PhonePDD == howToSale
*
*
*/
public abstract class AbstractSale {
private String type;
private Integer price;
public AbstractSale(String type,Integer price){
this.type = type;
this.price = price;
}
String getSaleInfo(){
return "渠道:"+type+"==>"+"价格:"+price;
}
void howToSale(){
//都不一样
}
}
那么接下来,我们可以为不同种的渠道进行抽象类的实现,这里主要实现线上渠道与线下渠道还有学生渠道三种:
/**
* 线上渠道
*/
public class OnlineSale extends AbstractSale{
public OnlineSale(String type, Integer price) {
super(type, price);
}
}
/**
* 线下渠道
*/
public class OfflineSale extends AbstractSale{
public OfflineSale(String type, Integer price) {
super(type, price);
}
}
public class StudentSale extends AbstractSale{
public StudentSale(String type, Integer price) {
super(type, price);
}
}
接下来我们在对手机的不同品牌来进行实现抽象类:
public class IPhone extends AbstractPhone{
@Override
String getPhone() {
return "IPhone:"+sale.getSaleInfo();
}
}
public class MiPhone extends AbstractPhone{
@Override
String getPhone() {
return "小米:";
}
}
这样我们就可以来编写我们的环境类(测试类或者外部组件调用类):
public class MainTest {
public static void main(String[] args) {
IPhone iPhone = new IPhone();
iPhone.setSale(new StudentSale("学生",1));
String phone = iPhone.getPhone();
System.out.println(phone);
}
}
这里我们就可以通过创建不同的渠道,通过该渠道中的价钱属性来定义不同品牌的手机在不同渠道中的价钱信息了,这样就免去了我们上述所提到n✖️m创建类的efforts了。
3. 应用场景
- 当一个类存在两个独立变化的维度,且这两个维度都需要进行扩展时。
- 当一个系统不希望使用继承或因为多层次继承导致系统类的个数急剧增加时。
- 当一个系统需要在构件的抽象化角色和具体化角色之间增加更多的灵活性时。
- InputStreamReader桥接模式。An InputStreamReader is a bridge from byte streams to character streams:
- InputStreamReader 桥接+适配器
- ...