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. 加载Firefox 和 chrome 浏览器配置

    Firefox: Chrome:

  2. java分割函数split的用法(二)

    package com.b; public class Sysetm { public static void main(String[] args) { String a=new String(&q ...

  3. AngularJS:简介

    ylbtech-AngularJS:简介 1.返回顶部 1. AngularJS 简介 AngularJS 是一个 JavaScript 框架.它可通过 <script> 标签添加到 HT ...

  4. 010. VS2015创建MVC项目

    1. 文件→新建→项目 2.选择空模板→选中MVC 3. 预览(如果是使用aspx, 则可以删除Views中的web.config, 如果使用Razor则不要删除, 否则会报Views/Home/In ...

  5. Linux quota命令参数及用法详解---Linux磁盘配额限制设置和查看命令

    功能说明:显示磁盘已使用的空间与限制. 语 法:quota [-quvV][用户名称...] 或 quota [-gqvV][群组名称...] 补充说明:执行quota指令,可查询磁盘空间的限制,并得 ...

  6. 谈谈contentWindow 和contentDocument以及 iframe

    1,contentWindow:是用来获取子窗口的window对象的,它兼容各大浏览器,用法如下 document.getElementById("iframeId").conte ...

  7. springMVC的多文件的异步上传实现

    springMVC的MultipartFile与传统的ajax文件上传兼容性不好,采用如下的ajax方法,后台无法获取文件. $.ajax({ url: '/upload', type: 'POST' ...

  8. 带你剖析WebGis的世界奥秘----Geojson数据加载(高级)(转)

    带你剖析WebGis的世界奥秘----Geojson数据加载(高级) 转:https://zxhtom.oschina.io/zxh/20160819.html  编程  java  2016/08/ ...

  9. JS中的两种刷新方法以及区别和适用范围

    在项目中有一个人信息修改的页面,但是修改后显示的却是修改之前的内容,分析问题后发现查询语句写在了修改语句之前,有些某些需要又必须这么写,但是修改信息后先却显示之前的信息也太不科学了. 所以我就想用js ...

  10. Java中迭代Map的方法

    Map<String, String> mapServlet = new HashMap<String, String>(); System.out.println(" ...