深入理解Java设计模式之桥接模式
作者:一指流砂~ 发布时间:2022-04-11 07:34:53
一、什么是桥接模式
桥接模式(Bridge Pattern
):将抽象部分与它的实现部分分离,使它们都可以独立地变化。它是一种对象结构型模式,又称为柄体(Handle and Body
)模式或接口(Interface
)模式。
二、桥接模式的结构
在桥接模式结构图中包含如下几个角色:
Abstraction
(抽象类):用于定义抽象类的接口,它一般是抽象类而不是接口,其中定义了一个Implementor(实现类接口)类型的对象并可以维护该对象,它与Implementor之间具有关联关系,它既可以包含抽象业务方法,也可以包含具体业务方法。RefinedAbstraction
(扩充抽象类):扩充由Abstraction定义的接口,通常情况下它不再是抽象类而是具体类,它实现了在Abstraction中声明的抽象业务方法,在RefinedAbstraction中可以调用在Implementor中定义的业务方法。Implementor
(实现类接口):定义实现类的接口,这个接口不一定要与Abstraction的接口完全一致,事实上这两个接口可以完全不同,一般而言,Implementor接口仅提供基本操作,而Abstraction定义的接口可能会做更多更复杂的操作。Implementor接口对这些基本操作进行了声明,而具体实现交给其子类。通过关联关系,在Abstraction中不仅拥有自己的方法,还可以调用到Implementor中定义的方法,使用关联关系来替代继承关系。ConcreteImplementor
(具体实现类):具体实现Implementor接口,在不同的ConcreteImplementor中提供基本操作的不同实现,在程序运行时,ConcreteImplementor对象将替换其父类对象,提供给抽象类具体的业务操作方法。
三、桥接模式的使用场景
当对象存在多种变化的因素时,考虑对其变化的因素和场景进行抽象,然后进行桥接;如笔拥有不同的功能。
当多个对象存在多种变化的因素时,考虑将这部分变化的部分抽象出来再聚合进来;比如不同品牌的电脑安装不同的系统、使用不同的软件等,相当于将第一条进行横向扩展,增加桥接的数量。
四、桥接模式的优缺点
优点:
(1)分离抽象接口及其实现部分。桥接模式使用“对象间的关联关系”解耦了抽象和实现之间固有的绑定关系,使得抽象和实现可以沿着各自的维度来变化。所谓抽象和实现沿着各自维度的变化,也就是说抽象和实现不再在同一个继承层次结构中,而是“子类化”它们,使它们各自都具有自己的子类,以便任何组合子类,从而获得多维度组合对象。
(2)在很多情况下,桥接模式可以取代多层继承方案,多层继承方案违背了“单一职责原则”,复用性较差,且类的个数非常多,桥接模式是比多层继承方案更好的解决方法,它极大减少了子类的个数。
(3)桥接模式提高了系统的可扩展性,在两个变化维度中任意扩展一个维度,都不需要修改原有系统,符合“开闭原则”。
缺点:
(1)桥接模式的使用会增加系统的理解与设计难度,由于关联关系建立在抽象层,要求开发者一开始就针对抽象层进行设计与编程。
(2)桥接模式要求正确识别出系统中两个独立变化的维度,因此其使用范围具有一定的局限性,如何正确识别两个独立维度也需要一定的经验积累。
五、装饰,桥接和适配器模式的异同
三者都是结构型的设计模式,而且都存在依赖抽象的情况
适配器模式:
重点强调的是适配的功能。(适配器依赖抽象)
关键点是:
主体类和适配器类实现相同的接口A
主体类依赖适配器类
适配器类依赖抽象接口B
被适配的类实现抽象接口B
最终的效果就是,主体类可以使用之前不相关的被适配类中的某些功能。
桥接模式:
重点强调的是多维度的变化。(主体类直接依赖抽象)
关键点是:
主体类依赖抽象A
主体类具有多个不同的实现类
抽象A具有多个不同的实现类
最终的效果就是,主体类的实现类和抽象的实现类分别可以在两个维度上进行各自的变化。如果主体类依赖多个抽象,则维度进行增加,方便扩展。
装饰器模式:
重点强调的是装饰功能。(主体类不仅依赖抽象,而且实现该抽象接口)
关键点是:
抽象A具有多个具体子类
装饰器类依赖抽象A
装饰器类实现抽象A
装饰器类存在不同子类
最终的效果就是,(装饰器实现类)对(原抽象的子类)进行某些方法的功能加强。
六、桥接模式的实现
首先抽象出电视机,提供遥控器改变的行为方法。
/// <summary>
/// 电视机,提供抽象方法
/// </summary>
public abstract class TV
{
public abstract void On();
public abstract void Off();
public abstract void tuneChannel();
}
创建具体的电视机,继承自抽象电视机类:
/// <summary>
/// 三星牌电视机,重写基类的抽象方法
/// </summary>
public class Samsung:TV
{
public override void On()
{
Console.WriteLine("三星牌电视机已经打开了");
}
public override void Off()
{
Console.WriteLine("三星牌电视机已经关掉了");
}
public override void tuneChannel()
{
Console.WriteLine("三星牌电视机换频道");
}
}
/// <summary>
/// 长虹牌电视机,重写基类的抽象方法
/// 提供具体的实现
/// </summary>
public class ChangHong : TV
{
public override void On()
{
Console.WriteLine("长虹牌电视机已经打开了");
}
public override void Off()
{
Console.WriteLine("长虹牌电视机已经关掉了");
}
public override void tuneChannel()
{
Console.WriteLine("长虹牌电视机换频道");
}
}
然后抽象出概览中的遥控器,扮演抽象话的角色
/// <summary>
/// 抽象概念中的遥控器,扮演抽象化角色
/// </summary>
public abstract class RemoteControl
{
public TV implementor { get; set; }
/// <summary>
/// 开电视机
/// 这里抽象类中不再提供实现了,而是调用实现类中的实现
/// </summary>
public virtual void On()
{
implementor.On();
}
/// <summary>
/// 关电视机
/// </summary>
public virtual void Off()
{
implementor.Off();
}
/// <summary>
/// 换频道
/// </summary>
public virtual void SetChannel()
{
implementor.tuneChannel();
}
}
创建具体遥控器类:这里面,我重写了更换频道的方法,其实还可以重写其他的方法
/// <summary>
/// 具体遥控器类
/// </summary>
public class ConcreteRemote:RemoteControl
{
/// <summary>
/// 重写更换频道方法
/// </summary>
public override void SetChannel()
{
Console.WriteLine("重写更换频道方法");
base.SetChannel();
}
}
客户端代码:
static void Main(string[] args)
{
// 创建一个遥控器
RemoteControl remoteControl = new ConcreteRemote();
//长虹电视机
remoteControl.implementor = new ChangHong();
remoteControl.On();
remoteControl.SetChannel();
remoteControl.Off();
Console.WriteLine();
// 三星牌电视机
remoteControl.implementor = new Samsung();
remoteControl.On();
remoteControl.SetChannel();
remoteControl.Off();
Console.Read();
}
这样接实现了桥接模式的设计,遥控器的功能实现方法不是在遥控器中去实现了,而是将实现部分用来另一个电视机类去封装它,遥控器中只包含电视机类的一个引用,通过桥接模式,我们把抽象化和实现化部分分离开了,这样可以很好应对这两方面的变化。
七、总结
桥接模式是一个非常有用的模式,在桥接模式中体现了很多面向对象设计原则的思想,包括“单一职责原则”、“开闭原则”、“合成复用原则”、“里氏代换原则”、“依赖倒转原则”等。熟悉桥接模式有助于我们深入理解这些设计原则,也有助于我们形成正确的设计思想和培养良好的设计风格。
本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注脚本之家的更多内容!
来源:https://www.cnblogs.com/xuwendong/p/10319474.html


猜你喜欢
- 前言我们知道volatile关键字的作用是保证变量在多线程之间的可见性,它是java.util.concurrent包的核心,没有volat
- 本文实例讲述了Java简单实现调用命令行并获取执行结果。分享给大家供大家参考,具体如下:import java.io.BufferedRea
- 本文实例讲述了C#将HashTable中键列表或值列表复制到一维数组的方法。分享给大家供大家参考。具体如下:下面的示例说明如何将 Hasht
- springboot上传文件大小的配置我这里记录两种,一种是设置在配置文件里只有两行代码,一种是加个Bean首先第一种:applicatio
- 一直以来做对外的接口文档都比较原始,基本上都是手写的文档传来传去,最近发现了一个新玩具,可以在接口上省去不少麻烦。swagger是一款方便展
- 使用lombok插件的好处我们在java开发过程中,经常会有一些常规性的,重复性的工作。比如:根据成员变量生成get和set方法根据成员变量
- 我就废话不多说了,大家还是直接看代码吧~package c10; import java.util.Scanner; public clas
- 近期,Google宣布Kotlin成为了Android一级开发语言。于是就刚刚简单的研究了一下,查资料的时候发现现成的资料还是很少的,于是决
- 一、async和await特性的结构1. 异步和同步同步方法:如果一个方法被调用了,等待其执行所有处理后调用方法才继续执行的方法。异步方法:
- Java实现按行读取大文件String file = "F:" + File.separator + "a.t
- Java 实现 Http Server,模拟前端接口调用前言: 最近看到一个很有意思的东西,手写简单的 Http Server,而且只需要使
- 本文实例展示了C#自定义函数NetxtString实现生成随机字符串的方法,在进行C#项目开发中非常实用!分享给大家供大家参考。一、生成随机
- springboot创建线程池两种方式1.使用static代码块创建这样的方式创建的好处是当代码用到线程池的时候才会初始化核心线程数具体代码
- 在后台工程师开发完新代码交给QA进行测试时,软件测试人员一般都会要求后台开发对单元测试的覆盖率达到一定的标准;例如我们的标准是分支覆盖率达到
- PhotoView的简介:这是一个图片查看库,实现图片浏览功能,支持pinch(捏合)手势或者点击放大缩小。支持在ViewPager中翻页浏
- Android:控件GridView的使用如果是列表(单列多行形式)的使用ListView,如果是多行多列网状形式的优先使用GridView
- 如下所示:public class 字符串常用操作 { public static void main(String[] arg
- 简单介绍下功能1.每隔一段时间(比如1分钟)在京东手机每日一秒杀页面提取产品(手机)链接。 http://sale.360buy.com/a
- 1.File对象java封装的一个操作文件及文件夹(目录)的对象。可以操作磁盘上的任何一个文件和文件夹。2.创建文件方式一:根据路径构建一个
- 一、简介构造函数,基本用法是在类对象声明的时候完成初始化工作。二、实例构造函数1、构造函数的名字与类名相同。2、使用 new 表达式创建类的