• (十一)桥梁模式


    今天我要说说我自己,梦想中的我自己,我身价过亿,有两个大公司,一个是房地产公司,一个是服装制造
    业,这两个公司都很赚钱,天天帮我在累加财富,其实是什么公司我倒是不关心,我关心的是是不是在赚钱,赚
    了多少,这才是我关心的,我是商人呀,唯利是图是我的本性,偷税漏税是我的方法,欺上瞒下、压榨员工血汗
    我是的手段嘛,我先用类图表示一下我这两个公司: 
     
    类图很简单,声明了一个 Corp 抽象类,定义一个公司的抽象模型,公司首要是赚钱的,不赚钱谁开公司,
    做义务或善举那也是有背后利益支撑的,我还是赞成这句话“天下熙熙,皆为利来;天下壤壤,皆为利往”,那
    我们先看 Corp 类的源代码: 
     
    package com.cbf4life; 
     
    /** 
     * @author cbf4Life cbf4life@126.com 
     * I'm glad to share my knowledge with you all. 
     * 定义一个公司的抽象类 
     */ 
    public abstract class Corp {
      /* 
       * 是公司就应该有生产把,甭管是什么软件公司还是制造业公司 
       * 那每个公司的生产的东西都不一样,所以由实现类来完成 
       */ 
      protected abstract void  produce(); 
      
      /* 
       * 有产品了,那肯定要销售呀,不销售你公司怎么生存 
       */ 
      protected abstract void sell();  
      
      //公司是干什么的?赚钱的呀,不赚钱傻子才干 
      public void makeMoney(){ 
       
       //每个公司都是一样,先生产 
       this.produce(); 
       
       //然后销售 
       this.sell(); 
       
     } 
      

     
    合适的方法存在合适的类中,这个基本上是每本 Java基础书上都会讲的,但是到实际的项目中应用的时候
    就不是这么回事儿了,正常的很。我们继续看两个实现类如何实现的,先看 HouseCorp 类,这个是我最赚钱的
    公司: 
     
    package com.cbf4life; 
     
    /** 
     * @author cbf4Life cbf4life@126.com 
     * I'm glad to share my knowledge with you all. 
     * 房地产公司,按照翻译来说应该叫realty corp,这个是比较准确的翻译 
     * 但是我问你房地产公司翻译成英文,你第一反应什么?对嘛还是house corp! 
     */ 
    public class HouseCorp extends Corp { 
      
      //房地产公司就是盖房子 
      protected void produce() { 
      System.out.println("房地产公司盖房子..."); 
     }
     
      //房地产卖房子,自己住那可不赚钱 
      protected void sell() { 
      System.out.println("房地产公司出售房子..."); 
     } 
      
      //房地产公司很High了,赚钱,计算利润 
      public void makeMoney(){ 
       super.makeMoney(); 
      System.out.println("房地产公司赚大钱了..."); 
     } 
     

     
    然后看服装公司,虽然不景气,但好歹也是赚钱的: 
     
    package com.cbf4life; 
     
    /** 
     * @author cbf4Life cbf4life@126.com 
     * I'm glad to share my knowledge with you all. 
     * 服装公司,这个行当现在不怎么样 
     */ 
    public class ClothesCorp extends Corp { 
      
      //服装公司生产的就是衣服了 
      protected void produce() { 
      System.out.println("服装公司生产衣服..."); 
     } 
     
      //服装公司买服装,可只卖服装,不买穿衣服的模特 
      protected void sell() { 
      System.out.println("服装公司出售衣服..."); 
     } 
      
      //服装公司不景气,但怎么说也是赚钱行业也 
      public void makeMoney(){ 
       super.makeMoney(); 
      System.out.println("服装公司赚小钱..."); 
     } 
     

    两个公司都有了,那肯定有人会关心两个公司的运营情况呀,我自己怎么也要知道它是生产什么的,赚多少
    钱吧,那看看这个 Client.java 是什么样子的: 
     
    package com.cbf4life; 
     
    /** 
     * @author cbf4Life cbf4life@126.com 
     * I'm glad to share my knowledge with you all. 
     * 我要关心我自己的公司了 
     */ 
    public class Client { 
     
      public static void main(String[] args) { 
      System.out.println("-------房地产公司是这个样子运行的-------"); 
       //先找到我的公司 
        HouseCorp houseCorp =new HouseCorp(); 
       //看我怎么挣钱 
      houseCorp.makeMoney(); 
      System.out.println(" "); 
       
      System.out.println("-------服装公司是这样运行的-------"); 
        ClothesCorp clothesCorp = new ClothesCorp(); 
      clothesCorp.makeMoney(); 
       
     } 

     
    看,这个代码很简单,运行结果如下: 
     
    -------房地产公司是这个样子运行的------- 
    房地产公司盖房子... 
    房地产公司出售房子... 
    房地产公司赚大钱了... 
     
     
    -------服装公司是这样运行的------- 
    服装公司生产衣服... 
    服装公司出售衣服... 
    服装公司赚小钱... 
     
    上述代码完全可以描述我现在的公司,但是你要知道万物都是运动的,你要用运动的眼光看问题,我公司也
    会发展,终于在有一天我觉得赚钱速度太慢,于是我上下疏通,左右打关系,终于开辟了一条赚钱的康庄大道:
    生产山寨产品,什么产品呢?就是市场上什么牌子的东西火爆我生产什么牌子的东西,甭管是打火机还是电脑,
    只要它火爆,我就生产,赚过了高峰期就换个产品,打一枪换一个牌子,不承担售后成本、也不担心销路问题,
    我只有正品的十分之一的价格,你买不买?哈哈,赚钱呀! 
    企业的方向定下来了,通过调查,市场上前段时间比较火爆的是苹果 iPod,那咱就生产这个,把服装厂该
    成 iPod 生产厂,看类图的变化: 
     
    好,我的企业改头换面了,开始生产 iPod 产品了,看我 IPodCorp 类的实现: 
     
    package com.cbf4life; 
     
    /** 
     * @author cbf4Life cbf4life@126.com 
     * I'm glad to share my knowledge with you all. 
     * 我是山寨老大,你流行啥我就生产啥 
     * 现在流行iPod 
     */ 
    public class IPodCorp extends Corp { 
      
      //我开始生产iPod了 
      protected void produce() {
      System.out.println("我生产iPod..."); 
     } 
     
      //山寨的iPod很畅销,便宜呀 
      protected void sell() { 
      System.out.println("iPod畅销..."); 
     } 
      
      //狂赚钱 
      public void makeMoney(){ 
       super.makeMoney(); 
      System.out.println("我赚钱呀..."); 
     } 
     

     
    这个厂子修改完毕了,我这个董事长还要去看看到底生产什么的,看这个 Client.java 程序: 
     
    package com.cbf4life; 
     
    /** 
     * @author cbf4Life cbf4life@126.com 
     * I'm glad to share my knowledge with you all. 
     * 我要关心我自己的公司了 
     */ 
    public class Client { 
     
      public static void main(String[] args) { 
      System.out.println("-------房地产公司是这个样子运行的-------"); 
       //先找到我的公司 
        HouseCorp houseCorp =new HouseCorp(); 
       //看我怎么挣钱 
      houseCorp.makeMoney(); 
      System.out.println(" "); 
       
      System.out.println("-------山寨公司是这样运行的-------"); 
        IPodCorp iPodCorp = new IPodCorp(); 
      iPodCorp.makeMoney(); 
       
     } 

    确实,只用修改了几句话,我的服装厂就开始变成山寨 iPod 生产车间,然后就看我的财富在积累积累,你
    想呀山寨的东西不需要特别的销售渠道(正品到哪里我就到哪里),不需要维修成本(大不了给你换个,你还想
    咋地,过了高峰期我就改头换面了你找谁维修去,投诉?投诉谁呢?),不承担广告成本(正品在打广告,我还
    需要吗?需要吗?),但是我也有犯愁的时候,我这是个山寨工厂,要及时的生产出市场上流行产品,转型要快,
    要灵活,今天从生产 iPod 转为生产 MP4,明天再转为生产上网本,这个都需要灵活的变化,不要限制的太死,
    那问题来了,每次我的厂房,我的工人,我的设备都在,不可能每次我换个山寨产品我的厂子就彻底不要了,这
    不行,成本忒高了点,那怎么办? 
    Thinking,Thinking…,I got an idea!,这样设计: 
     
     
     
    Corp 类和 Product 类建立一个关联关系,可以彻底解决我以后山寨公司生产产品的问题,看程序说话,
    先看 Product 抽象类: 
     
    package com.cbf4life.implementor; 
     
    /** 
     * @author cbf4Life cbf4life@126.com 
     * I'm glad to share my knowledge with you all. 
     * 这是我整个集团公司的产品类 
     */ 
    public abstract class Product { 
      
      //甭管是什么产品它总要是能被生产出来 
      public abstract void beProducted(); 
      
      //生产出来的东西,一定要销售出去,否则扩本呀 
      public abstract void beSelled(); 
      

     
    简单,忒简单了,看 House 产品类: 
     
    package com.cbf4life.implementor; 
     
    /** 
     * @author cbf4Life cbf4life@126.com 
     * I'm glad to share my knowledge with you all. 
     * 这是我集团公司盖的房子 
     */ 
    public class House extends Product { 
     
      //豆腐渣就豆腐渣呗,好歹也是个房子 
      public void beProducted() { 
      System.out.println("生产出的房子是这个样子的..."); 
     } 
     
      //虽然是豆腐渣,也是能够销售出去的 
      public void beSelled() { 
      System.out.println("生产出的房子卖出去了..."); 
     } 
     

     
    不多说,看 Clothes 产品类: 
     
    package com.cbf4life.implementor; 
     
    /** 
     * @author cbf4Life cbf4life@126.com 
     * I'm glad to share my knowledge with you all. 
     * 我集团公司生产的衣服 
     */ 
    public class Clothes extends Product { 
     
      public void beProducted() {
      System.out.println("生产出的衣服是这个样子的..."); 
     } 
      
      public void beSelled() { 
      System.out.println("生产出的衣服卖出去了..."); 
     } 
     

     
    下面是 iPod产品类: 
     
    package com.cbf4life.implementor; 
     
    /** 
     * @author cbf4Life cbf4life@126.com 
     * I'm glad to share my knowledge with you all. 
     * 生产iPod了 
     */ 
    public class IPod extends Product { 
     
      public void beProducted() { 
      System.out.println("生产出的iPod是这个样子的..."); 
     } 
      
      public void beSelled() { 
      System.out.println("生产出的iPod卖出去了..."); 
     } 
     

     
    产品类是有了,那我们再看 Corp 抽象类: 
     
    package com.cbf4life.abstraction; 
     
    import com.cbf4life.implementor.Product; 
     
    /** 
     * @author cbf4Life cbf4life@126.com 
     * I'm glad to share my knowledge with you all. 
     * 定义一个公司的抽象类 
     */ 
    public abstract class Corp { 
      
      //定义一个产品对象,抽象的了,不知道具体是什么产品 
      private Product product; 
      
      //构造函数,由子类定义传递具体的产品进来 
      public Corp(Product product){ 
       this.product = product; 
     } 
      
      //公司是干什么的?赚钱的呀,不赚钱傻子才干 
      public void makeMoney(){ 
       
       //每个公司都是一样,先生产 
       this.product.beProducted(); 
       
       //然后销售 
       this.product.beSelled(); 
       
     } 
      
      

     
    这里多了个有参构造,其目的是要继承的子类都必选重写自己的有参构造函数,把产品类传递进来,再看子
    类 HouseCorp 的实现: 
     
    package com.cbf4life.abstraction; 
     
    import com.cbf4life.implementor.House; 
     
    /** 
     * @author cbf4Life cbf4life@126.com 
     * I'm glad to share my knowledge with you all. 
     * 房地产公司,按照翻译来说应该叫realty corp,这个是比较准确的翻译 
     * 但是我问你房地产公司翻译成英文,你第一反应什么?对嘛还是house corp! 
     */ 
    public class HouseCorp extends Corp { 
      
      //定义传递一个House产品进来 
      public HouseCorp(House house){ 
       super(house); 
     } 
       
      //房地产公司很High了,赚钱,计算利润 
      public void makeMoney(){ 
       super.makeMoney(); 
      System.out.println("房地产公司赚大钱了..."); 
     } 
     

     
    理解上没有多少难度,不多说,继续看山寨公司的实现: 
     
    package com.cbf4life.abstraction; 
     
    import com.cbf4life.implementor.Product; 
     
    /** 
     * @author cbf4Life cbf4life@126.com 
     * I'm glad to share my knowledge with you all. 
     * 我是山寨老大,你流行啥我就生产啥 
     */ 
    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 程序: 
     
    package com.cbf4life; 
     
    import com.cbf4life.abstraction.HouseCorp; 
    import com.cbf4life.abstraction.ShanZhaiCorp; 
    import com.cbf4life.implementor.Clothes; 
    import com.cbf4life.implementor.House; 
     
    /** 
     * @author cbf4Life cbf4life@126.com 
     * I'm glad to share my knowledge with you all. 
     * 我要关心我自己的公司了 
     */ 
    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(" "); 
       
       //山寨公司生产的产品很多,不过我只要指定产品就成了 
      System.out.println("-------山寨公司是这样运行的-------"); 
        ShanZhaiCorp shanZhaiCorp = new ShanZhaiCorp(new Clothes()); 
      shanZhaiCorp.makeMoney(); 
       
     } 

     
    运行结果如下: 
     
    -------房地产公司是这个样子运行的------- 
    生产出的房子是这个样子的... 
    生产出的房子卖出去了... 
    房地产公司赚大钱了... 
     
     
    -------山寨公司是这样运行的------- 
    生产出的衣服是这个样子的... 
    生产出的衣服卖出去了... 
    我赚钱呀... 
     
    这个山寨公司的前身是生产衣服的,那我现在要修改一下,生产 iPod,看如下的变化: 
     
    package com.cbf4life; 
     
    import com.cbf4life.abstraction.HouseCorp; 
    import com.cbf4life.abstraction.ShanZhaiCorp; 
    import com.cbf4life.implementor.House; 
    import com.cbf4life.implementor.IPod; 
     
    /** 
     * @author cbf4Life cbf4life@126.com 
     * I'm glad to share my knowledge with you all. 
     * 我要关心我自己的公司了 
     */ 
    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(" "); 
       
       //山寨公司生产的产品很多,不过我只要制定产品就成了 
      System.out.println("-------山寨公司是这样运行的-------"); 
       //ShanZhaiCorp shanZhaiCorp = new ShanZhaiCorp(new Clothes()); 
        ShanZhaiCorp shanZhaiCorp = new ShanZhaiCorp(new IPod()); 
      shanZhaiCorp.makeMoney(); 
       
     } 

    运行结果如下: 
     
    -------房地产公司是这个样子运行的------- 
    生产出的房子是这个样子的... 
    生产出的房子卖出去了... 
    房地产公司赚大钱了... 
     
     
    -------山寨公司是这样运行的------- 
    生产出的iPod是这个样子的... 
    生产出的iPod卖出去了... 
    我赚钱呀... 
     
    看代码上的黄色底色的代码,就修改了这一一句话代码就完成了生产产品的转换。那我们深入的思考一下,
    既然万物都是运动的,我现在只有房地产公司和山寨公司,那以后我会不会增加一些其他的公司呢?或者房地产
    公司会不会对业务进行细化,比如分为公寓房公司,别墅公司,以及商业房公司等等呢?那我告诉你,会的,绝
    对的会的,但是你发觉没,这种变化对我们上面的类图没有大的修改,充其量是扩展,你看呀: 
    增加公司,你要么继承 Corp 类,要么继承 HouseCorp 或 ShanZhaiCorp,不用再修改原有的类了; 
    增加产品,继承 Product类,或者继承 House 类,你要把房子分为公寓房、别墅、商业用房等等; 
    你都是在扩展,唯一你要修改的就是 Client 类,你类都增加了哪能不修改调用呢,也就是说 Corp 类和
    Product 类都可以自由的扩展,而不会对整个应用产生太的变更,这就是桥梁模式。 
    为什么叫桥梁模式?我们看一下桥梁模式的通用类图: 
     
    看到中间那根带箭头的线了吗?是不是类似一个桥,连接了两个类?所以就叫桥梁模式。我们再把桥梁模式
    的几个概念熟悉一下, 大家有没有注意到我把Corp类以及它的两个实现类放到了Abstraction包中, 把House
    以及相关的三个实现类放到了 Implementor 包中,这两个包分别对应了桥梁模式的业务抽象角色
    (Abstraction)和业务实现角色 (Implementor),这两个角色我估计没几个人能说的明白,特别是看了“四
    人帮”的书或者是那本非常有名的、比砖头还要厚的书,你会越看越糊涂,忒专业化,有点像看政府的红头文件,
    什么都说了,可好像又什么都没有说。这两个角色大家只要记住一句话就成:业务抽象角色引用业务实现角色,
    或者说业务抽象角色的部分实现是由业务实现角色完成的,很简单,别想那么复杂了。 
    桥梁模式的优点就是类间解耦,我们上面已经提到,两个角色都可以自己的扩展下去,不会相互影响,这个
    也符合 OCP原则。 
     
    今天说到桥梁模式,那就多扯几句,大家对类的继承有什么看法吗?继承的优点有很多,可以把公共的方法
    或属性抽取,父类封装共性,子类实现特性,这是继承的基本功能,缺点有没有?有,强关联关系,父类有个方
    法,你子类也必须有这个方法,是不可选择的,那这会带来扩展性的问题,我举个简单的例子来说明这个问题:
    Father 类有一个方法 A,Son 继承了这个方法,然后 GrandSon 也继承了这个方法,问题是突然有一天 Son
    要重写父类的这个方法,他敢做吗?绝对不敢!GrandSon 可是要用从 Father 继承过来的方法 A,你修改了,
    那就要修改 Son 和 GrandSon 之间的关系,那这个风险就大了去。 
    今天讲的这个桥梁模式就是这一问题的解决方法,桥梁模式描述了类间弱关联关系,还说上面的那个例子,
    Fater 类完全可以把可能会变化的方法放出去,Son 子类要有这个方法很简答,桥梁搭过去,获得这个方法,
    GrandSon 也一样,即使你 Son 子类不想使用这个方法了,也没关系,对 GrandSon 不产生影响,他不是从你
    Son 中继承来的方法! 
    继承不能说它不好,非常好,但是有缺点的,我们可以扬长避短,对于比较明确不发生变化的,则通过继承
    来完成,若不能确定是否会发生变化的,那就认为是会发生变化,则通过桥梁模式来解决,这才是一个完美的世
    界。 

    如果一件事情你觉得难的完不成,你可以把它分为若干步,并不断寻找合适的方法。最后你发现你会是个超人。不要给自己找麻烦,但遇到麻烦绝不怕,更不要退缩。 电工查找电路不通点的最快方法是:分段诊断排除,快速定位。你有什么启示吗? 求知若饥,虚心若愚。 当你对一个事情掌控不足的时候,你需要做的就是“梳理”,并制定相应的规章制度,并使资源各司其职。
  • 相关阅读:
    【原】费马小定理(Fermat little theorem)详解
    【原】水库抽样详解
    【原】模幂运算(Modular Exponentiation)算法
    【原】 POJ 3630 Phone List Trie树 解题报告
    【Joke】你可以去当程序员了
    【原】 POJ 3750 小孩报数问题 Joseph相关问题详解 解题报告
    【原】 POJ 3748 位操作 解题报告
    react 性能优化
    修改jsp文件,访问时没有变化。可能是修改了系统的时间,,,郁闷呢
    在Windows 7 下使用Visual Studio 2010 编写自动申请管理员权限运行的程序
  • 原文地址:https://www.cnblogs.com/wvqusrtg/p/4812991.html
Copyright © 2020-2023  润新知