桥接模式简介
桥接模式定义
桥接模式(Bridge Pattern),也叫做桥梁模式,结构型设计模式的一种,这个模式相对来说有些难理解。桥接,顾名思义,就是用来连接两个部分,为被分离了的抽象部分和实现部分搭桥。
主要作用将抽象与实现分离,使它们可以独立变化。它是用组合关系代替继承关系来实现,从而降低了抽象和实现这两个可变维度的耦合度
桥接模式是一种很实用的结构型设计模式,如果软件系统中某个类存在两个独立变化的维度,通过该模式可以将这两个维度分离出来,使两者可以独立扩展,让系统更加符合“单一职责原则”。与多层继承方案不同,它将两个独立变化的维度设计为两个独立的继承等级结构,并且在抽象层建立一个抽象关联,该关联关系类似一条连接两个独立继承结构的桥,故名桥接模式。
桥接模式包含以下角色:
- (Abstraction)抽象化角色:它的主要职责是定义出该角色的行为, 同时保存一个对实现化角色的引用, 该角色一般是抽象类。
- (Implementor)实现化角色:它是接口或者抽象类, 定义角色必需的行为和属性,供扩展抽象化角色调用。
- (RefinedAbstraction)扩展抽象化:它引用实现化角色对抽象化角色进行修正,并通过组合关系调用实现化角色中的业务方法。
- (ConcreteImplementor)具体实现化角色:它实现接口或抽象类定义的方法和属性
桥接模式优缺点:
优点:
- 实现了抽象和实现部分的分离:桥接模式分离了抽象部分和实现部分,从而极大的提供了系统的灵活性,让抽象部分和实现部分独立开来,分别定义接口,这有助于系统进行分层设计,从而产生更好的结构化系统。对于系统的高层部分,只需要知道抽象部分和实现部分的接口就可以了。在该模式下, 实现可以不受抽象的约束, 不用再绑定在一个固定的抽象层次上。
- 更好的可扩展性:由于桥接模式把抽象部分和实现部分分离了,从而分别定义接口,这就使得抽象部分和实现部分可以分别独立扩展,而不会相互影响,大大的提供了系统的可扩展性。
- 其实现细节对客户透明:客户不用关心细节的实现, 它已经由抽象层通过聚合关系完成了封装。
- 可动态的切换实现:由于桥接模式实现了抽象和实现的分离,所以在实现桥接模式时,就可以实现动态的选择和使用具体的实现。
- 符合开闭原则
- 符合合成复用原则
缺点:
- 桥接模式的使用会增加系统的理解与设计难度,由于关联关系建立在抽象层,要求开发这一开始就针对抽象层进行设计与编程
- 桥接模式要求正确识别出系统中两个独立变化的维度,因此,适用范围有一定的局限性,正确识别两个维度也需要一定的经验积累
使用场景
(1)如果一个系统需要在构件的抽象化角色和具体化角色之间增加更多的灵活性,避免在两个层次之间建立静态的继承联系,通过桥接模式可以使它们在抽象层建立一个关联关系。
(2)抽象化角色和实现化角色可以以继承的方式独立扩展而互不影响,在程序运行时可以动态将一个抽象化子类的对象和一个实现化子类的对象进行组合,即系统需要对抽象化角色和实现化角色进行动态耦合。
(3)一个类存在两个独立变化的维度,且这两个维度都需要进行扩展。
(4)虽然在系统中使用继承是没有问题的,但是由于抽象化角色和具体化角色需要独立变化,设计要求需要独立管理这两者。
(5)对于那些不希望使用继承或因为多层次继承导致系统类的个数急剧增加的系统,桥接模式尤为适用。
以下举一个桥接模式的例子:
将实现与抽象放在两个不同的类层次中,使两个层次可以独立改变
人在吃水果,这里有两个维度的变化,人有不同的人,水果也也有多种
person类(实现化角色):
/**
* person类(实现化角色)
*/
public interface Person {
public void eat();
}
具体的person:小明(具体实现化角色)
/**
* 具体的person:小明(具体实现化角色)
*/
public class xiaoMing implements Person {
@Override
public void eat() {
System.out.println("小明在吃");
}
}
具体的person:小李(具体实现化角色)
/**
* 具体的person:小李(具体实现化角色)
*/
public class xiaoLi implements Person {
@Override
public void eat() {
System.out.println("小李在吃");
}
}
抽象的水果类(抽象化角色):
/**
* 抽象的水果(抽象化角色)
*/
public abstract class Fruit {
protected Person person;
protected Fruit(Person person){
this.person = person;
}
public abstract void personEatFruit();
}
具体的水果:苹果(具体实现化角色)
/**
* 具体的水果:苹果(具体实现化角色)
*/
public class apple extends Fruit{
public apple(Person person) {
super(person);
}
@Override
public void personEatFruit() {
super.person.eat();
System.out.println("苹果");
}
}
具体的水果:梨(具体实现化角色)
/**
* 具体的水果:梨(具体实现化角色)
*/
public class pear extends Fruit{
public pear(Person person) {
super(person);
}
@Override
public void personEatFruit() {
super.person.eat();
System.out.println("梨");
}
}
测试类:
/**
* 测试类
*/
public class teat {
public static void main(String[] args) {
Fruit appleXiaoMing = new apple(new xiaoMing());
appleXiaoMing.personEatFruit();
Fruit pearXiaoMing = new pear(new xiaoMing());
pearXiaoMing.personEatFruit();
Fruit appleXiaoLi = new apple(new xiaoLi());
appleXiaoLi.personEatFruit();
Fruit pearXiaoLi = new pear(new xiaoLi());
pearXiaoLi.personEatFruit();
}
}
输出结果如下所示:
小明在吃
苹果
小明在吃
梨
小李在吃
苹果
小李在吃
梨
从结果可以看出实现了扩展抽象类与具体实现类的组合,如果增加吃其他水果类型,那就新建个类型继承Fruit类就可以了。
总而言之:
- 桥接模式中不仅Implementor具有变化 ,而且Abstraction也可以发生变化,而且两者的变化是完全独立的
- 桥接模式的目的是分离抽象和实现部分,使得它们可以独立的变化。且策略模式仅仅通过Abstraction与 Implementor之间的关系联系起来。
- 对于桥接模式的定义:将抽象和实现解耦,让它们可以独立变化。
这里的“抽象”,指的并非“抽象类”或“接口”,而是被抽象出来的一套“类库”,它只包含骨架代码,真正的业务逻辑需要委派给定义中的“实现”来完成。而定义中的“实现”,也并非“接口的实现类”,而是的一套独立的“类库”。“抽象”和“实现”独立开发,通过对象之间的组合关系,组装在一起。
以上代码下载请点击该链接:https://github.com/Yarrow052/Java-package.git