在日常开发过程中时常需要用到设计模式,但是设计模式有23种,如何将这些设计模式了然于胸并且能在实际开发过程中应用得得心应手呢?和我一起跟着《Android源码设计模式解析与实战》一书边学边应用吧!
设计模式系列文章
- Android 设计模式之单例模式
- Android 设计模式之Builder模式
- Android 设计模式之观察者模式
- Android 设计模式之代理模式
- Android 设计模式之装饰模式
- Android 设计模式之外观模式
- Android 设计模式之原型模式
- Android 设计模式之工厂方法模式
- Android 设计模式之策略模式
- Android 设计模式之适配器模式
- Android 设计模式之状态模式
- Android 设计模式之面向对象的六大原则
今天我们要讲的是桥接模式(Bridge Pattern)
定义
将抽象部分与实现部分分离,使它们都可以独立地变化
使用场景
- 任何多维度变化类或者说多个树状类之间的耦合都可以使用桥接模式来实现解耦
- 如果一个系统需要在构件的抽象化角色和具体化角色之间增加更多的灵活性,避免在2个层次之间建立静态的继承关系,可以通过桥接模式使它们在抽象层建立一个关联关系
- 对于那些不希望使用继承或因为多层次继承导致系统类的个数急剧增加的系统,也可以考虑使用桥接模式
- 一个类存在2个独立变化的维度,且这2个维度都需要进行扩展
使用例子
- Adapter与AdapterView
- View的视图层级中,TextView等控件和View之间构成一个继承关系的视图层级,而将控件绘制到屏幕的是与View相关的功能实现类,如Canvas、DisplayList等,这2部分之间的关系可以看作是对桥接模式的应用
- 对于Android来说,应用层与Native层之间的交互也是桥接模式的很好的例子
实现
4大角色
- 抽象部分:这部分保持对实现部分对象的引用,抽象部分中的方法需要调用实现部分的对象来实现
- 优化的抽象部分:抽象部分的具体实现,一般是对抽象部分的方法进行完善和扩展
- 实现部分:可以为接口或抽象类,其方法不一定要与抽象部分中的一致,一般情况下是由实现部分提供基本的操作,而由抽象部分定义的则是基于实现部分这些基本操作的业务方法
- 实现部分的具体实现:完善实现部分中的方法定义的具体逻辑
实现的要点
- 桥接模式定义中的“抽象”和“实现”实质上是对应2个独立变化的维度,而不能仅仅简单理解为抽象就是抽象类和接口,实现就是对抽象的实现
- 桥接模式的实现关键在于对抽象和实现的分离的把握
- 在分离出抽象和实现之后,抽象部分抽象出业务方法,由子类去实现;实现部分抽象出基本的操作,也由子类去实现
- 抽象部分的抽象类持有实现部分的抽象引用,以便在抽象部分中加入实现部分的具体操作逻辑,这样便在抽象层建立了一个关联关系
实现方式
这里我们通过泡咖啡的例子来简单看看桥接模式的实现和应用
- 咖啡简单分大杯小杯,加不加糖。泡咖啡就是业务逻辑,而加不加糖则是基本操作,这样我们把泡咖啡定为抽象部分,子类具体实现是大杯还是小杯;加不加糖则为实现部分,对应子类则实现加不加糖。
- 抽象部分,也就是咖啡类,CoffeeAdditives为实现部分也就是加不加糖,impl为实现部分的引用
public abstract class Coffee {
protected CoffeeAdditives impl;
public Coffee (CoffeeAdditives impl) {
this.impl = impl;
}
/**
* 咖啡具体是什么样的由子类决定
*/
public abstract void makeCoffee();
}
- 咖啡的子类,大杯和小杯,加不加糖的操作通过impl添加进来
//大杯咖啡
public class LargeCoffee extends Coffee {
public LargeCoffee(CoffeeAdditives coffeeAdditives) {
super(coffeeAdditives);
}
@Override
public void makeCoffee() {
System.out.println("大杯的" + impl.addSomething() + "咖啡");
}
}
//小杯咖啡
public class SmallCoffee extends Coffee {
public SmallCoffee(CoffeeAdditives coffeeAdditives) {
super(coffeeAdditives);
}
@Override
public void makeCoffee() {
System.out.println("小杯的" + impl.addSomething() + "咖啡");
}
}
- 下面我们看看实现部分,也就是加不加糖
public abstract class CoffeeAdditives {
/**
* 具体添加什么东西由子类决定
*
* @return 添加的东西,比如加糖
*/
public abstract String addSomething();
}
- 加糖和不加糖的子类
//加糖
public class Sugar extends CoffeeAdditives {
@Override
public String addSomething() {
return "加糖";
}
}
//不加糖,这里就是原味了
public class Ordinary extends CoffeeAdditives {
@Override
public String addSomething() {
return "原味";
}
}
- 以上抽象部分和实现部分都完成了,现在我们来看看怎么“泡咖啡”
//原味
Ordinary ordinary = new Ordinary();
//加糖
Sugar sugar = new Sugar();
//大杯咖啡,原味
LargeCoffee largeCoffee = new LargeCoffee(ordinary);
largeCoffee.makeCoffee();
//小杯咖啡,原味
SmallCoffee smallCoffee = new SmallCoffee(ordinary);
smallCoffee.makeCoffee();
//大杯咖啡,加糖
LargeCoffee largeCoffeeSugar = new LargeCoffee(sugar);
largeCoffeeSugar.makeCoffee();
//小杯咖啡,加糖
SmallCoffee smallCoffeeSugar = new SmallCoffee(sugar);
smallCoffeeSugar.makeCoffee();
- 输出日志
大杯的原味咖啡
小杯的原味咖啡
大杯的加糖咖啡
小杯的加糖咖啡
通过以上的例子我们可以看出桥接模式能够分离抽象与实现,而且扩展也很灵活。比如我们需要添加个中杯的咖啡,只需要在抽象部分,也就是写个Coffee的子类MiddleCoffee就行了,而实现部分,CoffeeAdditives则不受影响。如果咖啡需要加盐或是其他什么的同样也很简单。
总结
- 桥接模式的关键在于分离抽象部分和实现部分,这2部分的分离也不是绝对的。比如上面的例子,我们当然也可以把添加东西作为抽象部分,而把大杯小杯作为实现部分
- 桥接模式通过依赖抽象达到解耦的目的,而且扩展性也很好,可以应用的地方有很多。
- 桥接模式需要分离抽象和实现,需不需要分离、怎么分离?还是需要权衡。
欢迎关注我的微信公众号,期待与你一起学习,一起交流,一起成长!
AntDream
网友评论