Bridge 桥接模式(结构型模式)

抽象与实现

抽象不应该依赖于实现细节,实现细节应该依赖于抽象。

抽象B稳定,实现细节b变化

问题在于如果抽象B由于固有的原因,本身并不稳定,也有可能变化,怎么办?

举例来说

  假如我们需要开发一个同时支持PC和手机的坦克游戏,游戏在PC和手机上功能都一样,都有同样的类型,面临同样的需求变化,比如坦克可能有多种不同的型号:T50,T75,T90……

对于其中坦克设计,我们可能很容易设计出来一个Tank的抽象基类:

    /// <summary>
/// 抽象Tank
/// </summary>
public abstract class Tank
{
public abstract void Shot();
public abstract void Run();
public abstract void Turn();
} //各种实现
public class T50 : Tank
{
//……
}
public class T75 : Tank
{
//……
}
public class T90 : Tank
{
//……
}

另外的变化原因

但是PC和手机上的图形绘制、生效、操作等实现完全不同……因此对于各种型号的坦克,都要提供各种不同平台上的坦克的实现:

    //PC平台实现
public class PCT50 : T50
{
//……
}
public class PCT75 : T75
{
//……
}
public class PCT90 : T90
{
//……
}
//手机平台实现
public class MobileT50 : T50
{
//……
}
public class MobileT75 : T75
{
//……
}
public class MobileT90 : T90
{
//……
}

这样的设计会带来很多问题:有很多重复代码,类的结构过于复杂,难以维护,最致命的是引入任何新平台,比如在TV上的Tank游戏,都会让整个类层级结构复杂变化。

动机(Motivation)

思考上述问题的症结:事实上由于Tank类型的固有逻辑,使得Tank类型具有了两个变化的维度——一个变化的维度为“平台的变化”,一个变化的维度为“型号的变化”。

如何应对这种“多维度的变化”?如何利用面向对象技术使得Tank类型可以轻松地沿着“平台”和“型号”两个方向变化,而不引入额外的复杂度?

意图(Intent)

将抽象部分与现实部分分离,使它们可以独立地变化。——《设计模式》GoF

代码示例:

    //平台
public abstract class TankPlatformImplementation
{
public abstract void MoveTankTo(Point to);
public abstract void DrawTank();
public abstract void DoShot();
}
//PC平台
public class PCTankImplementation : TankPlatformImplementation
{
public override void MoveTankTo(Point to)
{
//……
} public override void DrawTank()
{
//……
} public override void DoShot()
{
//……
}
}
//手机平台
public class MobileTankImplementation : TankPlatformImplementation
{
public override void MoveTankTo(Point to)
{
//……
} public override void DrawTank()
{
//……
} public override void DoShot()
{
//……
}
}
    /// <summary>
/// 抽象Tank
/// </summary>
public abstract class Tank
{
protected TankPlatformImplementation tankImpl; public Tank(TankPlatformImplementation tankImpl)
{
this.tankImpl = tankImpl;
} public TankPlatformImplementation TankImpl
{
get { return this.tankImpl; }
set { this.tankImpl = tankImpl; }
}
public abstract void Shot();
public abstract void Run();
public abstract void Turn();
}
    //各种实现
public class T50 : Tank
{
public T50(TankPlatformImplementation tankImpl):base(tankImpl)
{ }
public override void Shot()
{
//……
} public override void Run()
{
//……
} public override void Turn()
{
//……
}
}
public class T75 : Tank
{
public T75(TankPlatformImplementation tankImpl):base(tankImpl)
{ }
public override void Shot()
{
//……
} public override void Run()
{
//……
} public override void Turn()
{
//……
}
}
public class T90 : Tank
{
public T90(TankPlatformImplementation tankImpl):base(tankImpl)
{ }
public override void Shot()
{
//……
} public override void Run()
{
//……
} public override void Turn()
{
//……
}
}
    //调用
public class App
{
public static void Main()
{
TankPlatformImplementation tankImpl=new MobileTankImplementation();//手机平台调用
T50 tankT50=new T50(tankImpl);
}
}

将一个事物中多个维度的变化分离,使它们可以独立地变化

Bridge模式的几个要点

Bridge模式使用“对象间的组合关系”解耦了抽象和现实之间固有的绑定关系,使得抽象(Tank的型号)和实现(不同的平台)可以沿着各自的维度来变化。

所谓抽象和实现可以沿着各自维度变化,即“子类化”它们,比如Tank型号子类,和不同的平台子类。得到各个子类之后,便可以任意组合它们,从而获得不同平台的不同型号。

Bridge模式有时候类似于多继承方案,但是多继承方案往往违背单一职责原则(即一个类只有一个变化的原因),复用性比较差。Bridge模式是比多继承方案更好的解决办法。

Bridge模式的应用一般在“两个非常强的变化维度”,有时候即使有两个变化的维度,但是某个方向的变化维度并不剧烈——换言之两个变化不会导致纵横交错的结果,并不一定要使用Bridge模式。

设计模式07: Bridge 桥接模式(结构型模式)的更多相关文章

  1. .NET设计模式(15):结构型模式专题总结(转)

    摘要:结构型模式,顾名思义讨论的是类和对象的结构,它采用继承机制来组合接口或实现(类结构型模式),或者通过组合一些对象,从而实现新的功能(对象结构型模式).这些结构型模式,它们在某些方面具有很大的相似 ...

  2. 设计模式(十二): Flyweight享元模式 -- 结构型模式

    说明: 相对于其它模式,Flyweight模式在PHP实现似乎没有太大的意义,因为PHP的生命周期就在一个请求,请求执行完了,php占用的资源都被释放.我们只是为了学习而简单做了介绍. 1. 概述 面 ...

  3. 代理模式/proxy模式/结构型模式

    代理模式proxy 定义 为其他对象提供一种代理,并以控制对这个对象的访问.最简单的理解,买东西都是要去商店的,不会去工厂. java实现三要素 proxy(代理)+subject(接口)+realS ...

  4. Bridge桥接模式(结构型模式)

    现有一个需求,一个游戏系统需要构建不同风格的房屋,暂不考虑其他设计模式,需要能实现在PC端.移动端....等等多个平台的构建.最简单的实现方式如下: /// <summary> /// 房 ...

  5. 设计模式(十三): Proxy代理模式 -- 结构型模式

      设计模式(十一)代理模式Proxy(结构型) 1.概述 因为某个对象消耗太多资源,而且你的代码并不是每个逻辑路径都需要此对象, 你曾有过延迟创建对象的想法吗 ( if和else就是不同的两条逻辑路 ...

  6. 设计模式学习之路——Facade 外观模式(结构型模式)

    动机: 组件的客户和组件中各种复杂的子系统有了过多的耦合,随着外部客户程序和各子系统的演化,这种过多的耦合面临很多变化的挑战.如何简化外部客户程序和系统间的交互接口?如何将外部客户程序的演化和内部子系 ...

  7. 设计模式(十):Decorator装饰者模式 -- 结构型模式

    1. 概述 若你从事过面向对象开发,实现给一个类或对象增加行为,使用继承机制,这是所有面向对象语言的一个基本特性.如果已经存在的一个类缺少某些方法,或者须要给方法添加更多的功能(魅力),你也许会仅仅继 ...

  8. 设计模式(十一):FACADE外观模式 -- 结构型模式

    1. 概述 外观模式,我们通过外观的包装,使应用程序只能看到外观对象,而不会看到具体的细节对象,这样无疑会降低应用程序的复杂度,并且提高了程序的可维护性.例子1:一个电源总开关可以控制四盏灯.一个风扇 ...

  9. 设计模式(八):Bridge桥接模式 -- 结构型模式

    1. 概述 在软件系统中,某些类型由于自身的逻辑,它具有两个或多个维度的变化,那么如何应对这种“多维度的变化”?如何利用面向对象的技术来使得该类型能够轻松的沿着多个方向进行变化,而又不引入额外的复杂度 ...

  10. 设计模式(九):Composite组合模式 -- 结构型模式

    1. 概述 在数据结构里面,树结构是很重要,我们可以把树的结构应用到设计模式里面. 例子1:就是多级树形菜单. 例子2:文件和文件夹目录 2.问题 我们可以使用简单的对象组合成复杂的对象,而这个复杂对 ...

随机推荐

  1. hive字段原理--有删除一列想到的

    hive删除一张表的字段不会动数据文件,只是修改了一下metadata表里面的表定义:所以会出现一种情况:就是这张表如果之前数据是满的(个格列都有数据),那么被删除的那列后数据都往前窜了一个,最后一个 ...

  2. (转)Android和JavaScript互相调用

    Html页面和Java代码结合的方式一般用在界面经常被更改 的情况下,可以讲html放在网络中,软件一打开就会访问网络获取到最新的界面.缺点是会受到网络信号的影响,从而导致访问速度慢. 1.用WebV ...

  3. 深入浅出MFC学习笔记 消息

    本章将会对MFC的消息映射和 命令传递机制做深入探讨. MFC规定了消息传递的路线,消息会按照这个路线传递下去,找不到归宿的话就交给DefWindowProc. 在产生窗口之前,如果我们在创建窗口时指 ...

  4. gitlab的本地搭建和部署使用

    公司现在的代码管理是在公司的服务器上部署了gitlab,这样既方便协同开发,有可以很好的保护代码的安全性. 那么我们就来研究一下 如何给自己的服务器上部署gitlab吧! 学习源头:https://w ...

  5. php小算法总结一(数组重排,进制转换,二分查找)

    1.两个有序数组组合成一个新的有序数组 <?php $arr1=array(2,5,7,9,12); $arr2=array(3,4,6,8,10,11); function merge_sor ...

  6. 杂项:WiKi

    ylbtech-杂项:WiKi Wiki是一种在网络上开放且可供多人协同创作的超文本系统,由沃德·坎宁安于1995年首先开发,这种超文本系统支持面向社群的协作式写作,同时也包括一组支持这种写作.沃德· ...

  7. python开发函数进阶:装饰器

    一,装饰器本质 闭包函数 功能:就是在不改变原函数调用方式的情况下,在这个函数前后加上扩展功能 作用:解耦,尽量的让代码分离,小功能之前的分离. 解耦目的,提高代码的重用性 二,设计模式 开放封闭原则 ...

  8. VC6编写的Dll调试方法

    Dll工程运行时指定调用exe程序. 关键!!往往被忽略:exe中也一定要指向此调用dll,如果指向不对,什么效果也没有!

  9. 不用jquery实现tab页切换,刷新,后退,前进状态自动维护 很好用

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  10. Make Cents

    Every year, an elephant qualifies to the Arab Collegiate Programming Competition. He graduated this ...