桥接模式基于类的最小设计原则,通过使用封装,聚合及继承等行为让不同的类承担不同的职责。也就是说,将实现与抽象放在两个不同的类层次中,使两个层次可以独立改变。从而可以保持各部分的独立性以及能够应对它们的功能扩展。
一个咖啡店可以提供大杯(JorumCoffee)、中杯(MediumCoffee)、小杯(SmallCoffee)的咖啡(Coffee),为了满足不同用户的口味,在咖啡中可以添加牛奶(Milk),或者糖(Sugar),或者柠檬(Lemon),提供给用户不同口味的组合,如大杯咖啡加牛奶,中杯咖啡加糖,小杯咖啡加柠檬,小杯咖啡加糖等。冲咖啡的流程:磨咖啡,导入杯中,选择调味品,加入咖啡中,出售。
下面使用桥接模式设计该系统并绘制相应的类图,并用面向对象编程语言实现该模式。
抽象化角色,Coffee类:
public abstract class Coffee {
protected Condiment Condiment;
/**
* 磨咖啡豆
*/
public void grindCoffeeBean() {
System.out.println("磨咖啡豆");
}
/**
* 倒咖啡豆到杯中
*/
public abstract void putIntoCup();
/**
* 选择调味品
*/
public void selectCondiment() {
// TODO Auto-generated method stub
System.out.println("选择调味品:【" + this.Condiment.getName() + "】");
}
/**
* 加入咖啡中
*/
public abstract void addToCoffee();
/**
* 出售
*/
public void sell() {
grindCoffeeBean();
putIntoCup();
selectCondiment();
addToCoffee();
System.out.println("出售");
}
}
大杯咖啡JorumCoffee类:
public class JorumCoffee extends Coffee {
public JorumCoffee(Condiment condiment) {
// TODO Auto-generated constructor stub
this.Condiment = condiment;
System.out.println("客户选择的组合套餐是:大杯咖啡+" + condiment.getName());
System.out.println("开始制作该套餐》》》》》》");
}
@Override
public void putIntoCup() {
// TODO Auto-generated method stub
System.out.println("倒入磨好的咖啡豆到大杯中");
}
@Override
public void addToCoffee() {
// TODO Auto-generated method stub
System.out.println("将调料加入到大杯咖啡中");
}
}
中杯咖啡MediumCoffee类:
public class MediumCoffee extends Coffee {
public MediumCoffee(Condiment condiment) {
// TODO Auto-generated constructor stub
this.Condiment = condiment;
System.out.println("客户选择的组合套餐是:中杯咖啡+" + condiment.getName());
System.out.println("开始制作该套餐》》》》》》");
}
@Override
public void putIntoCup() {
// TODO Auto-generated method stub
System.out.println("倒入磨好的咖啡豆到中杯中");
}
@Override
public void addToCoffee() {
// TODO Auto-generated method stub
System.out.println("将调料加入到中杯咖啡中");
}
}
小杯咖啡 SmallCoffee 类:
public class SmallCoffee extends Coffee {
public SmallCoffee(Condiment condiment) {
// TODO Auto-generated constructor stub
this.Condiment = condiment;
System.out.println("客户选择的组合套餐是:小杯咖啡+" + condiment.getName());
System.out.println("开始制作该套餐》》》》》》");
}
@Override
public void putIntoCup() {
// TODO Auto-generated method stub
System.out.println("倒入磨好的咖啡豆到小杯中");
}
@Override
public void addToCoffee() {
// TODO Auto-generated method stub
System.out.println("将调料加入到小杯咖啡中");
}
}
抽象类:
public interface Condiment {
public String getName();
}
public class Lemon implements Condiment {
@Override
public String getName() {
// TODO Auto-generated method stub
return "柠檬";
}
}
public class Milk implements Condiment {
@Override
public String getName() {
// TODO Auto-generated method stub
return "牛奶";
}
}
public class Sugar implements Condiment {
@Override
public String getName() {
// TODO Auto-generated method stub
return "糖";
}
}
Client客户类进行测试;
public class Client {
public static void main(String[] args) {
// 大杯咖啡加牛奶
Condiment condiment01 = new Milk();
Coffee coffee01 = new JorumCoffee(condiment01);
coffee01.sell();
// 中杯咖啡加糖
Condiment condiment02 = new Sugar();
Coffee coffee02 = new MediumCoffee(condiment02);
coffee02.sell();
// 小杯咖啡加柠檬
Condiment condiment03 = new Lemon();
Coffee coffee03 = new SmallCoffee(condiment03);
coffee03.sell();
}
}
桥接模式在JDBC中的应用,JDBC中的connection接口,要连接不同的数据库需要独自实现该接口,在DriverManager类中提供了重载的获取connection的方法getConnection。connection接口就是实现化角色,针对不同数据库的Connection接口实现类就是具体实现化角色。
与传统的桥接模式不同,DriverManager类没有抽象层父类。上述的类相关的简略UML类图如下:
桥接模式实现了抽象和实现部分的分离,从而极大地提高了系统的灵活性,让抽象部分和实现部分独立开,这有助于系统进行分层设计,从而产生更好的结构化系统。
桥接模式替代多层继承方案,可以减少子类的个数,降低系统的管理和维护成本
桥接模式的引入增加了系统的理解和设计难度,由于聚合关联关系建立在抽象层,因此其使用范围有一定的局限性。
桥接模式的优点:
桥接模式的缺点:
桥接模式的引入会增加系统的理解与设计难度,由于聚合关联关系建立在抽象层,要求开发者针对抽象进行设计与编程。 - 桥接模式要求正确识别出系统中两个独立变化的维度,因此其使用范围具有一定的局限性。
应用场景:
桥接模式通常适用于以下场景。
当一个类存在两个独立变化的维度,且这两个维度都需要进行扩展时。
当一个系统不希望使用继承或因为多层次继承导致系统类的个数急剧增加时。
当一个系统需要在构件的抽象化角色和具体化角色之间增加更多的灵活性时。
参考:
1.http://c.biancheng.net/view/1364.html
2.https://design-patterns.readthedocs.io/zh_CN/latest/structural_patterns/bridge.html