桥梁模式

桥梁模式的定义

桥梁模式也叫做桥接模式
定义:将抽象和实现解耦,使得两者可以独立地变化。
桥梁模式的重点是在“解耦”上,如何让他们解耦是我们要了解的重点(说白了,就是把变化的部分抽取出来,由原来的继承关系,变成组合关系)
通用类图如下:

角色的定义

  • Abstraction——抽象化角色
    它的主要职责是定义出该角色的行为,同时保存一个对实现化角色的引用,该角色一般是抽象类。
  • Implementor——实现化角色
    它是接口或者抽象类,定义角色必须的行为和属性。
  • RefinedAbstraction——修正抽象化角色
    它引用实现化角色对抽象化角色进行修正。
  • ConcreteImplementor——具体实现化角色
    它实现接口或抽象类定义的方法和属性。

桥梁模式中的几个名词比较拗口,大家只要记住一句话就成:抽象角色引用实现角色,或者说抽象角色的部分实现是由实现角色完成的。通用源码如下:
实现化角色

public interface Implementor {
     //基本方法
     public void doSomething();
     public void doAnything();
}

他没有任何特殊的地方,就是一个一般接口,定义要实现的方法
具体实现化角色

public class ConcreteImplementor1 implements Implementor{
     public void doSomething(){
             //业务逻辑处理
     }
     public void doAnything(){
             //业务逻辑处理
     }
}
public class ConcreteImplementor2 implements Implementor{
     public void doSomething(){
             //业务逻辑处理
     }
     public void doAnything(){
             //业务逻辑处理
     }
}

抽象化角色

public abstract class Abstraction {
     //定义对实现化角色的引用
     private Implementor imp;
     //约束子类必须实现该构造函数
     public Abstraction(Implementor _imp){
             this.imp = _imp;
     }
     //自身的行为和属性
     public void request(){
             this.imp.doSomething();
     }
     //获得实现化角色
     public Implementor getImp(){
             return imp;
     }
}

加一个构造函数的作用是:提醒子类,必须做这项工作,指定实现者,特别是已经明确了实现者,则尽量清晰明确地定义出来。
具体抽象化角色

public class RefinedAbstraction extends Abstraction {
     //覆写构造函数
     public RefinedAbstraction(Implementor _imp){
             super(_imp);
     }
     //修正父类的行为
     @Override
     public void request(){
             /*
              * 业务处理...
              */
             super.request();
             super.getImp().doAnything();
     }
}

在构造函数中出入一个明确的实现者,代码会比较清晰。
场景类

public class Client {
     public static void main(String[] args) {
             //定义一个实现化角色
             Implementor imp = new ConcreteImplementor1();
             //定义一个抽象化角色
             Abstraction abs = new RefinedAbstraction(imp);
             //执行行文
             abs.request();
     }
}

桥梁模式是一个非常简单的模式,它只是使用了类间的聚合关系、继承、覆写等常用功能,但是它却提供了一个非常清晰、稳定的架构。

桥梁模式的应用

桥梁模式的优点

  • 抽象和实现分离
    这也是桥梁模式的主要特点,它完全是为了解决继承的缺点而提出的设计模式。在该模式下,实现可以不受抽象的约束,不用再绑定一个固定的抽象层次上。
  • 优秀的扩充能力
    增加实现,增加抽象都比较简单。
  • 实现细节对客户透明
    客户不用关系细节实现,它已经由抽象层通过聚合关系完成了封装。

桥梁模式的使用场景

  • 不希望或不适用使用继承的场景
    例如继承层次过渡、无法更细化设计颗粒等场景,需要考虑使用桥梁模式。
  • 接口或抽象类不稳定的场景
    明知道接口不稳定还想通过实现或继承来实现业务需求,那是得不偿失的,也是比较失败的做法。
  • 重用性要求较高的场景
    设计的颗粒度越细,则被重用的可能性就越大,而采用继承则受父类的限制,不可能出现太细的颗粒度。

桥梁模式的注意事项

桥梁模式是非常简单的,使用该模式时主要考虑如何拆分抽象和实现,并不是一涉及继承就要考虑使用该模式,那还要继承干什么呢?桥梁模式的意图还是对变化的封装,尽量把可能变化的因素封装到最细、最小的逻辑单元中,避免风险扩散。

简单示例

模拟不同公司,生产不同的产品,其中一家山寨公司需经常变换生产的产品
类图如下:


抽象产品类

public abstract class Product {
     //甭管是什么产品它总要能被生产出来
     public abstract void beProducted();
     //生产出来的东西,一定要销售出去,否则亏本
     public abstract void beSelled();
}

房子

public class House extends Product {
     //豆腐渣就豆腐渣呗,好歹也是房子
     public void beProducted() {
             System.out.println("生产出的房子是这样的...");
     }
     //虽然是豆腐渣,也是能够销售出去的
     public void beSelled() {
             System.out.println("生产出的房子卖出去了...");
     }
}

既然是产品类,那肯定有两种行为要存在:被生产和被销售,否则就不能称为产品了。
IPod产品

public class IPod extends Product {
     public void beProducted() {
             System.out.println("生产出的iPod是这样的...");
     }
     public void beSelled() {
             System.out.println("生产出的iPod卖出去了...");
     }
}

抽象公司

public abstract class Corp {
     //定义一个抽象的产品对象,不知道具体是什么产品
     private Product product;
     //构造函数,由子类定义传递具体的产品进来
     public Corp(Product product){
             this.product = product;
     }
     //公司是干什么的?赚钱的!
     public void makeMoney(){
             //每家公司都是一样,先生产
             this.product.beProducted();
             //然后销售
             this.product.beSelled();
     }
}

这里多了个有参构造,其目的是要继承的子类都必选重写自己的有参构造函数,把产品类传递进来,再看子类HouseCorp的实现。
房地产公司

public class HouseCorp extends Corp {
     //定义传递一个House产品进来
     public HouseCorp(House house){
             super(house);
     }
     //房地产公司很High了,赚钱,计算利润
     public void makeMoney(){
             super.makeMoney();
             System.out.println("房地产公司赚大钱了...");
     }
}

山寨公司

public class ShanZhaiCorp extends Corp {
      //产什么产品,不知道,等被调用的才知道
     public ShanZhaiCorp(Product product){
             super(product);
     }
     //狂赚钱
     public void makeMoney(){
             super.makeMoney();
             System.out.println("我赚钱呀...");
     }
}

HouseCorp类和ShanZhaiCorp类的区别是在有参构造的参数类型上,HouseCorp类比较明确,我就是只要House类,所以直接定义传递进来的必须是House类,一个类尽可能少地承担职责,那方法也一样,既然HouseCorp类已经非常明确地只生产House产品,那为什么不定义成House类型呢?ShanZhaiCorp就不同了,它确定不了生产什么类型。

好了,两大对应的阵营都经产生了。我们再看Client程序。
场景类

public class Client {
     public static void main(String[] args) {
             House house = new House();
             System.out.println("-------房地产公司是这样运行的-------");
             //先找到房地产公司
             HouseCorp houseCorp =new HouseCorp(house);
             //看我怎么挣钱
             houseCorp.makeMoney();
             System.out.println("\n");
             //山寨公司生产的产品很多,不过我只要指定产品就成了
             System.out.println("-------山寨公司是这样运行的-------");
             ShanZhaiCorp shanZhaiCorp = new ShanZhaiCorp(new IPod());
             shanZhaiCorp.makeMoney();
     }
}

突然有一天,老板良心发现了,不准备生产这种"三无”产品了,那我们程序该怎么修改呢?如果仍重操旧业,生产衣服,那该如何处理呢?很容易处理,增加一个产品类,然后稍稍修改一下场景就可以了,我们来看衣服产品类。
服装

public class Clothes extends Product {
     public void beProducted() {
             System.out.println("生产出的衣服是这样的...");
     }
     public void beSelled() {
             System.out.println("生产出的衣服卖出去了...");
     }
}

修改后的场景类

public class Client {
     public static void main(String[] args) {
             House house = new House();
             System.out.println("-------房地产公司是这样运行的-------");
             //先找到房地产公司
             HouseCorp houseCorp =new HouseCorp(house);
             //看我怎么挣钱
             houseCorp.makeMoney();
             System.out.println("\n");
             //山寨公司生产的产品很多,不过我只要指定产品就成了
             System.out.println("-------山寨公司是这样运行的-------");
             ShanZhaiCorp shanZhaiCorp = new ShanZhaiCorp(new Clothes());
             shanZhaiCorp.makeMoney();
     }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容