桥接模式
桥接模式,又叫桥梁模式,顾名思义,就是有座“桥”,那这座桥是什么呢?就是一条聚合线(下方UML图),比如我们下面会举的例子,手机有手机品牌和手机游戏等等,每个手机品牌都有多款游戏,那是不是二者之间就是聚合关系了,这是合成/聚合复用原则的体现,当我们发现类有多层继承时就可以考虑使用桥接模式,用聚合代替继承。
实例:手机品牌与软件之间的关系
UML图:
源代码:
package org.zangyu.bridge;
public class bridge {
public static void main(String[] args) {
// TODO Auto-generated method stub
HandsetBrand hb;
hb=new Xiaomi();//小米手机
hb.SetHandsetSoft(new Game());hb.Run();
hb.SetHandsetSoft(new AddressList());hb.Run();
hb=new Huawei();//华为手机
hb.SetHandsetSoft(new Game()); hb.Run();
hb.SetHandsetSoft(new AddressList()); hb.Run();
hb.SetHandsetSoft(new Mp3()); hb.Run();
}
}
//手机软件
abstract class HandsetSoft
{
public abstract void Run();
}
//手机品牌
abstract class HandsetBrand
{
protected HandsetSoft soft;
//设置手机软件
public void SetHandsetSoft(HandsetSoft soft) {
this.soft=soft;
}
//运行
public abstract void Run();
}
class Xiaomi extends HandsetBrand//小米
{
@Override
public void Run() {
// TODO Auto-generated method stub
System.out.println("小米手机");
soft.Run();
}
}
class Huawei extends HandsetBrand//华为
{
@Override
public void Run() {
// TODO Auto-generated method stub
System.out.println("华为手机");
soft.Run();
}
}
//手机软件
class Game extends HandsetSoft{//手机游戏
@Override
public void Run() {
// TODO Auto-generated method stub
System.out.println("运行手机游戏");
}
}
class AddressList extends HandsetSoft{//手机通信录
@Override
public void Run() {
// TODO Auto-generated method stub
System.out.println("运行手机通信录");
}
}
class Mp3 extends HandsetSoft{//Mp3
@Override
public void Run() {
// TODO Auto-generated method stub
System.out.println("运行手机Mp3");
}
}
增加手机功能:
class Photo extends HandsetSoft{//拍照
@Override
public void Run() {
// TODO Auto-generated method stub
System.out.println("运行手机拍照");
}
}
增加手机品牌:
class Apple extends HandsetBrand//苹果手机
{
@Override
public void Run() {
// TODO Auto-generated method stub
System.out.println("Apple");
soft.Run();
}
}
客户端:
hb=new Apple();//苹果手机
hb.SetHandsetSoft(new Photo()); hb.Run();
框架:
package org.zangyu.bridge;
public class bridge1 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Abstraction ab;
ab=new RefinedAbstraction();
ab.SetImplementor(new A());
ab.Operation();
ab.SetImplementor(new B());
ab.Operation();
}
}
//Implementor类
abstract class Implementor
{
public abstract void Operation();
}
//具体实现类A
class A extends Implementor{
@Override
public void Operation() {
// TODO Auto-generated method stub
System.out.println("具体实现A的方法执行");
}
}
//具体实现类B
class B extends Implementor{
@Override
public void Operation() {
// TODO Auto-generated method stub
System.out.println("具体实现B的方法执行");
}
}
//Abstraction类
class Abstraction{
protected Implementor implementor;
public void SetImplementor(Implementor implementor)
{
this.implementor=implementor;
}
public void Operation()
{
implementor.Operation();
}
}
//RefinedAbstraction类
class RefinedAbstraction extends Abstraction{
public void Operation()
{
implementor.Operation();
}
}
桥接模式的应用:
1. 何时使用
系统可能有多个角度分类,每一种角度都可能变化时
2. 方法
把这种角度分类分离出来,让它们单独变化,减少它们之间的耦合(合成/聚合复用原则)
3. 优点
抽象和实现分离。桥梁模式完全是为了解决继承的缺点而提出的设计模式
优秀的扩展能力
实现细节对客户透明。客户不用关心细节的实现,它已经由抽象层通过聚合关系完成了封装
4. 缺点
会增加系统的理解与设计难度。由于聚合关联关系建立在抽象层,要求开发者针对抽象进行设计与编程
5. 使用场景
不希望或不适用使用继承的场景
接口或抽象类不稳定的场景
重用性要求较高的场景
6. 应用实例
开关。我们可以看到的开关是抽象的,不用管里面具体怎么实现
手机品牌与手机软件。两者间有一条聚合线,一个手机品牌可以有多个手机软件
7. 注意事项
不要一涉及继承就考虑该模式,尽可能把变化的因素封装到最细、最小的逻辑单元中,避免风险扩散
当发现类的继承有n层时,可以考虑使用该模式
以上部分摘取自朱红梅老师2020年5月的课件。