zoukankan      html  css  js  c++  java
  • (十一)桥梁模式

    今天我要说说我自己,梦想中的我自己,我身价过亿,有两个大公司,一个是房地产公司,一个是服装制造
    业,这两个公司都很赚钱,天天帮我在累加财富,其实是什么公司我倒是不关心,我关心的是是不是在赚钱,赚
    了多少,这才是我关心的,我是商人呀,唯利是图是我的本性,偷税漏税是我的方法,欺上瞒下、压榨员工血汗
    我是的手段嘛,我先用类图表示一下我这两个公司: 
     
    类图很简单,声明了一个 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 中继承来的方法! 
    继承不能说它不好,非常好,但是有缺点的,我们可以扬长避短,对于比较明确不发生变化的,则通过继承
    来完成,若不能确定是否会发生变化的,那就认为是会发生变化,则通过桥梁模式来解决,这才是一个完美的世
    界。 

    如果一件事情你觉得难的完不成,你可以把它分为若干步,并不断寻找合适的方法。最后你发现你会是个超人。不要给自己找麻烦,但遇到麻烦绝不怕,更不要退缩。 电工查找电路不通点的最快方法是:分段诊断排除,快速定位。你有什么启示吗? 求知若饥,虚心若愚。 当你对一个事情掌控不足的时候,你需要做的就是“梳理”,并制定相应的规章制度,并使资源各司其职。
  • 相关阅读:
    fn project 试用之后的几个问题的解答
    fn project 扩展
    fn project 生产环境使用
    fn project 对象模型
    fn project AWS Lambda 格式 functions
    fn project 打包Function
    fn project Function files 说明
    fn project hot functions 说明
    fn project k8s 集成
    fn project 私有镜像发布
  • 原文地址:https://www.cnblogs.com/wvqusrtg/p/4812991.html
Copyright © 2011-2022 走看看