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. (转)android平台下使用点九PNG技术

    “点九”是andriod平台的应用软件开发里的一种特殊的图片形式,文件扩展名为:.9.png 智能手机中有自动横屏的功能,同一幅界面会在随着手机(或平板电脑)中的方向传感器的参数不同而改变显示的方向, ...

  2. mysql中修改密码的方式

    参考地址:https://www.cnblogs.com/yang82/p/7794712.html mysql中修改用户密码的方式: 最简单的方法就是借助第三方工具Navicat for MySQL ...

  3. B/S与C/S的区别

    参考:http://www.cnblogs.com/groler/articles/2116905.html 一.概念 C/S结构:即Client/Server(客户机/服务器)结构,是大家熟知的软件 ...

  4. Yii2 Post请求的时候出现400错误

    Bad Request (#400) Unable to verify your data submission.   http://www.yiiframework.com/forum/index. ...

  5. AIX PowerHA (HACMP) Commands

    PowerHA(HACMP) Commands How to start cluster daemons (options in that order:  clstrmgr, clsmuxpd, br ...

  6. leetcode821

    vector<int> shortestToChar(string S, char C) { vector<int> V; ; int AYC[N]; ; ; i < S ...

  7. [原创]Spring JdbcTemplate 使用总结与经验分享

    引言 近期开发的几个项目,均是基于Spring boot框架的web后端项目,使用JdbcTemplate执行数据库操作,实际开发过程中,掌握了一些有效的开发经验,踩过一些坑,在此做个记录及总结,与各 ...

  8. C++中的explicit关键字 - 抑制隐式转换(转)

    在C++程序中很少有人去使用 explicit 关键字,不可否认,在平时的实践中确实很少能用的上.再说C++的功能强大,往往一个问题可以利用好几种C++特性去解决.但稍微留心一下就会发现现有的MFC库 ...

  9. 微信小程序中出现Invoking Page() in async task.问题

    在做项目中需要让页面跳到外网,用到了<web-view src=""> </web-view>组件,需要新建一个文件放这个组件,调接口的时候链接连到这个页面 ...

  10. Money Systems 货币系统(母函数)

    Description 母牛们不但创建了他们自己的政府而且选择了建立了自己的货币系统. [In their own rebellious way],,他们对货币的数值感到好奇. 传统地,一个货币系统是 ...