美文网首页
桥梁模式

桥梁模式

作者: 缓慢移动的蜗牛 | 来源:发表于2019-12-04 19:57 被阅读0次

    桥梁模式的定义

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

    角色的定义

    • 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();
         }
    }
    

    相关文章

      网友评论

          本文标题:桥梁模式

          本文链接:https://www.haomeiwen.com/subject/ajzlgctx.html