面与卤的鹊桥相会——桥接模式

本文来自:崔成龙博客专栏。转载请注明出处:http://blog.csdn.net/xiaoxian8023

    软考上午题终于考完了。三个赶考者都感觉不错。检查了2遍,提前30分钟都出来了 。

    小A,小B,小C楼下碰头,相视一笑,轻松之感溢于言表。遂决定去吃面,以犒劳自己的肚子。

   “老板,我要西红柿鸡蛋面!”,“尖椒炸酱面!”,“苏格兰打卤面!”。。。。。。“好嘞!”

    面快出锅了,“哎哎,老板,怎么我的面跟他的面一样啊,就是换了一下卤?”往面里放卤的服务员翻了小B一眼,不搭理。旁边那个年长点的师傅笑了笑,说道“小兄弟儿,这你就不懂了吧。其实面都是一样的,只是换一下卤罢了。”“哦哦,原来如此啊。”小B灰溜溜得端起面来跑开了。。。

    面毕,小B实在是咽不下这口气。就想在小C那儿“捞回点儿本来”。

    “小C,面吃的怎么样啊?”小B阴阳怪气的问道。

    小C看着小B的表情,觉得有点不对劲,自己是不是又要上当了,但是又想不出来自己哪留有什么“把柄”,然后就答道,

    “还,还行吧,问这干嘛??”

    “嘿,你怕什么呀。我考一个关于吃面的题目”

    “嗨,我还以为什么呢,随便考吧,哥是来者不拒。”小C心里想到,就你那智商,能出什么样的难题呢,等着被鄙视吧。

    “你感觉自家煮面和饭馆煮面有什么不同?”

    “这还用问!感觉不同呗。自己煮面,自己累死了还得做饭,又是炒卤,又是煮面的,最低也得折腾半小时吧。饭馆多好啊,只要吆喝一声,人家都给你做好,端到你面前了。而且速度超快的。连这个都不知道。也对,就你那智商,好吧,我原谅你,哈哈哈哈”

    “哼,别笑得太早了。同样是面?你说为什么感觉不同啊”

    “呃,这个嘛,嗯,让我想想”小C装傻了。。。

    “哈,有点意思哎。我给你说说看看对不。”小A憋不住了。接着说道,

    “刚才小C说了,自家煮面,你必须自己做卤,自己煮面。每次想吃面的时候,这两步都是少不了的。但是面馆不一样啊。饭馆卤都是提前做好的。你点了面后,面馆给你煮面,然后加上你要的卤不就OK了吗!而且速度超快。比自己做饭省事多了。”

    “哦~,原来如此。”

    “我说那会那个服务员像看白痴的一样看我呀。”小B嘀咕道

    “what,what!!原来你被吃瘪了啊,哈哈”小C得意得捧腹大笑。

    小A眼睛一转,对即将要发飙的小B说道,

    “既然是你提出来的,你说说饭馆为什么要这么做呢?”

    “呃,嗯,,,,我想,应该是为了更快捷,方便地方便用户,同时提高自己的效率吧。”

    “还有没有别的?”

    小B想了半天,摇来摇头,“想不到了”

    “提示一点,面馆在增加新类型面的时候,是怎么做的?”

    “哦~~,我知道了,因为面差不多是一样的,只需要准备卤就行了。”

    “嗯,对的。其实面也是有不同的。比如说宽面,拉面,圆面。这样一组合,新的类型的面就出炉了。”

    “原来面馆里也有这么大学问啊。”

    “那是当然。365行,行行出状元啊。先不说这个了,既然说道这个面了,那你用面向对象写写刚才我们讨论的这件事儿吧。”

    “好。我试试吧”小B自信道。

     既然是面向对象,那么先把类找出来吧。首先有原料(Material),下分为面(Noodles)和卤(Halogen)。面有宽面条(WideNoodles),窄面条(NarrowNoodles)等多种类型,卤菜有西红柿鸡蛋卤(TomatoAndEgg),茄子豆瓣酱(AubergineBeanPaste)等多种卤菜。  西红柿鸡蛋面类(TomatoEggNoodles)为西红柿鸡蛋卤和宽面构成,而苏格兰打卤面(ScotlandNoodles)则是有茄子
豆瓣酱和窄面构成的。

先画出UML图:

uml图1.0版

    “看看怎么样啊”,小B得瑟的说道。

    “你有没有考虑代码的实现呢?”小A用看白痴的眼神扫了小B一眼,“除了C++,还有几个面向对象的有多继承啊!”

    “呃,这个,失误失误,我马上改!”

    “别急啊,还有错误呢,西红柿鸡蛋面有两部分构成,那肯定是用聚合或者是组合啊,不应该用继承的”小A提醒道。

    “哦,原来如此,我说怎么感觉有点不对劲呢,等着吧”

    5分钟过后。。。

    “哦,终于出来了,看看这次怎么样啊。”

uml图2.0.版

    “西红柿鸡蛋面和苏格兰打卤面的组成关系也画出来了。嗯不错,不过还有一点不对劲。假如我现在加一个新类型的面——西红柿鸡蛋卤面(窄面),你怎么加”

    “那就从面条类里泛化一个西红柿鸡蛋卤面(窄面)类,然后再在它上面加上与西红柿鸡蛋卤和窄面的组合关系”

    “那如果我现在面馆开10个分面馆,每个分面馆新增10样类,你是不是这100种面都要重新添加一遍面和卤的组合关系吧。”

    “那我还不得累死啊,这种活干不得!”小B惶恐的说道。

    “不管累,当你画出UML图的时候,能把你乱死。成品面与具体的面类型和卤菜类型的耦合性就太高了。想办法松散这些耦合。”

    “那怎么办呢?”小B焦急的问道。

    “呃,提醒你一点,你先对比一下你这两版UML各自的特点。”

    “第一幅图继承关系比较明显,第二幅图则利用了组合关系,使其继承关系简单化了”

    “如果你把这两个图合成一个图呢?”

    “这,这,怎么合啊。”

    “看来还得我出马啊,看着昂”

UML图3.0版

    “不管什么打卤面,都抽象于卤面类。卤面类由面条类和卤菜类组成。面条类和卤菜类都有各自的子类。”

    “这个图好面熟啊。让我想想昂。哦,对了,这不是桥接模式吗!”

    “是的,不过这样做有什么好处呢?”

    “这样做有几个好处,第一,松散耦合。具体的打卤面不再与具体的面类型和卤类型直接关联,松散了它们之间的耦合;第二,在变化方面,具体的打卤面, 具体的面类型和具体的卤类型各自的变化,互不影响”

    “这样我在开分面馆的时候就不用画那么多关系了,添加新类型的打卤面不再成为难事。果然很厉害。哈哈哈哈”小B得瑟的笑着,好像他真的要开面馆似的。

    “对头!这就满足了开闭原则,不用去修改,只需要添加即可。实例化具体的打卤面时,在客户端指定一下要哪种面,哪个卤即可。”小A接着说,

    “其实这里面最重要的是利用聚合组合关系,松散了耦合,使得抽象不再依赖于具体,而具体要依赖于抽象。”

    “哦,对哦。设计模式果然牛X。”

    “代码留在晚上再写吧,早点休息,下午还有考试呢!”小A看着一脸丫丫的小B,提醒道。

    “哦哦,差点忘了还有考试了。希望下午碰到桥接模式,那我就。。。”小B继续陷入丫丫ing。

    小A摇摇头,不再理睬小B,推开霸占自己床铺的小C,休息去了。

 

  面条类及子类

    #region  面条类及子类

    /// <summary>
    /// 面条类
    /// </summary>
    public abstract  class Noodles
    {
        public Noodles()
        {
        }

        /// <summary>
        /// 获取面类型名称
        /// </summary>
        /// <returns></returns>
        public abstract string GetName();

    }

    /// <summary>
    ///  窄面条
    /// </summary>
    public class  NarrowNoodles:Noodles
    {
        public NarrowNoodles()
        {
        }

        public override string GetName()
        {
            return "窄面条";
        }
    }

    /// <summary>
    /// 宽面条
    /// </summary>
    public class WideNoodles : Noodles
    {
        public WideNoodles()
        {
        }
        public override string GetName()
        {
            return "宽面条";
        }
    }

    #endregion

 卤菜类及子类

    #region 卤菜类及子类

    /// <summary>
    /// 卤菜类
    /// </summary>
    public abstract class Halogen
    {
        public Halogen()
        {
        }

        /// <summary>
        /// 获取卤菜名称
        /// </summary>
        /// <returns></returns>
        public abstract string GetName();
    }

    /// <summary>
    /// 西红柿鸡蛋卤
    /// </summary>
    public class TomatoAndEgg : Halogen
    {
        public TomatoAndEgg()
        {
        }
        public override  string GetName()
        {
            return "西红柿鸡蛋卤";
        }
    }

    /// <summary>
    /// 茄子豆瓣酱
    /// </summary>
    public class AubergineBeanPaste:Halogen
    {
        public AubergineBeanPaste()
        {
        }
        public override string GetName()
        {
            return "茄子豆瓣酱";
        }
    }

    #endregion

 

打卤面类及子类 

    #region 打卤面类及子类
    /// <summary>
    /// 打卤面类
    /// </summary>
    public class NoodlesAndHalogen
    {
        protected string name;
        protected Noodles noodles;
        protected Halogen halogen;

        public NoodlesAndHalogen(string name, Noodles noodles, Halogen halogen)
        {
            this.name=name;
            this.noodles = noodles;
            this.halogen = halogen;
        }

        /// <summary>
        /// 获取名称及成分
        /// </summary>
        public void  GetName()
        {
            Console.WriteLine("我是"+name+",由"+noodles.GetName () +"和"+halogen.GetName ()+"组成");
        }
    }

    /// <summary>
    /// 西红柿鸡蛋面
    /// </summary>
    public class TomatoEggNoodles : NoodlesAndHalogen
    {
        public TomatoEggNoodles(string name, Noodles noodles, Halogen halogen)
            : base(name, noodles, halogen)
        {
        }

    }

    /// <summary>
    /// 苏格兰打卤面
    /// </summary>
    public class ScotlandNoodles : NoodlesAndHalogen
    {
        public ScotlandNoodles(string name, Noodles noodles, Halogen halogen)
            : base(name, noodles,halogen)
        {
        }

    }

#endregion

 客户端代码: 

        static void Main(string[] args)
        {
            NoodlesAndHalogen n1=new TomatoEggNoodles("西红柿鸡蛋面(宽面)",new WideNoodles(),new TomatoAndEgg() );
            n1.GetName();
            NoodlesAndHalogen n2 = new ScotlandNoodles("苏格兰打卤面(窄面)", new NarrowNoodles(), new AubergineBeanPaste());
            n2.GetName();
            Console.Read();
        }

 运行结果:

 

 

时间: 2024-07-31 12:31:14

面与卤的鹊桥相会——桥接模式的相关文章

桥接模式之牛郎织女幸福牵手

  这是一个很美丽的,千古流传的爱情故事,每到农历七月初七,相传牛郎织女鹊桥相会的日子,牛郎和织女被银河隔开,只允许每年的农历七月七日相见.为了让牛郎和织女能顺利相会.各地的喜鹊就会飞过来用大家的身体紧贴着搭成一座桥,此桥就叫做鹊桥.牛郎和织女便在这鹊桥上相会.我就会抬头仰望星空,寻找银河两边的牛郎星和织女星,希望能看到他们一年一度的相会......   在牛郎织女相会的过程中,喜鹊是功不可没的大臣,我们今天的设计模式就从鹊桥开始说起---桥接模式,顾名思义,在接口与实现之间,架设一座桥梁,这座

php设计模式 Bridge (桥接模式)

复制代码 代码如下: <?php /** * 桥接模式 * * 将抽象部份与它实现部分分离,使用它们都可以有独立的变化 */ abstract class Implementor { abstract public function operation(); } class ConcreteImplementorA extends Implementor { public function operation() { echo "ConcreteImplementorA Operation

.NET下的设计模式研究之桥接模式

设计 概述 在软件系统中,某些类型由于自身的逻辑,它具有两个或多个维度的变化,那么如何应对这种"多维度的变化"?如何利用面向对象的技术来使得该类型能够轻松的沿着多个方向进行变化,而又不引入额外的复杂度?这就要使用Bridge模式. 意图 将抽象部分与实现部分分离,使它们都可以独立的变化.[GOF <设计模式>] 结构图 图1 Bridge模式结构图 生活中的例子 桥接模式将抽象部分与它的实现分离,使它们能够独立地变化.一个普通的开关控制的电灯.电风扇等等,都是桥接的例子.开

java中的桥接模式

桥接模式的英文是 Bridge ,桥接模式关注抽象的设计.抽象是指包含了一组抽象方法的类,这些抽象方 法可能包含多个实现. 实现抽象的一般做法是创建类的层次结构,该层次结构的顶部是一个包含抽象 方法的抽象类,该类的每一个子类都提供这些抽象方法的不同实现.但是,当需要对该层次进行子类化时,这 一做法就存在不足了. 你可以创建一个桥,然后把这些抽象方法移到接口中,这样,抽象就依赖于接 口的实现. 桥接模式的意图是:将抽象与抽象方法的实现相互分离来实现解耦,以便二者可以相互独 立的变化. 上面这段话的

.net设计模式实例之桥接模式( Bridge Pattern)

一.桥接模式简介(Brief Introduction) 桥接模式(Bridge Pattern),将抽象部分与它的实现部分分离,使的抽象和实现都可以独立地变化. Decouple an abstraction from its implementation so that the two can vary independently.. 什么是聚合/组合: 聚合(Aggregation),当对象A被加入到对象B中,成为对象B的组成部分时,对象B和对象A之间为聚合关系.聚合是关联关系的一种,是较

.NET设计模式(9):桥接模式(Bridge Pattern)

概述 在软件系统中,某些类型由于自身的逻辑,它具有两个或多个维度的变化,那么如何应对这种"多维度的变化"?如何利用面向对象的技术来使得该类型能够轻松的沿着多个方向进行变化,而又不引入额外的复杂度?这就要使用Bridge模式. 意图 将抽象部分与实现部分分离,使它们都可以独立的变化.[GOF <设计模式>] 结构图 图1 Bridge模式结构图 生活中的例子 桥接模式将抽象部分与它的实现分离,使它们能够独立地变化.一个普通的开关控制的电灯.电风扇等等,都是桥接的例子.开关的目

TP-Link TL-WDR6300 5G无线WDS桥接模式怎么设置

  设置TP-Link TL-WDR6300 5G无线WDS桥接模式步骤一.查看主路由器信息 请进入主路由器(已经连接到Internet的那台路由器)的设置界面,查看主路由器的无线信号名称(SSID ).加密方式.无线密码.信道这几个参数,并记录下来,如下图所示.SSID.zhangsan_5G;无线加密方式.WPA-PSK/WPA2-PSK;无线密码.1a2b3c4d;无线信道.157 设置TP-Link TL-WDR6300 5G无线WDS桥接模式步骤二.TL-WDR6300路由器WDS桥接

ADSL桥接模式与路由器模式的区别

早期国内的ADSL线路接入都是桥接方式,由ADSL MODEM和电脑配合,在电脑上分配固定IP地址,开机就能接入局端设备进入互联网.但是这样在用户不开机上网时,IP是不会被利用,会造成目前日益缺少 的公网IP资源的浪费,因此出现了PPPoE拨号的ADSL接入. PPPoE拨号可以使用户开机时拨号接入局端设备,由局端设备 分配给一个动态公网IP,这样公网IP紧张的局面就得到了缓解.目前国内的ADSL上网方式中,基本上是PPPoE拨号的方式.PPPoE拨号出现以 后,ADSL的接入设备--ADSL

《Python编程实战:运用设计模式、并发和程序库创建高质量程序》—— 2.2 桥接模式

2.2 桥接模式 "桥接模式"(Bridge Pattern)用于将"抽象"(abstraction,比如接口或算法)与实现方式相分离. 如果不用桥接模式,那么通常的写法是,创建若干个基类,用于表示各种抽象方式,然后从每个基类中继承出两个或多个子类,用于表示对这种抽象方式的不同实现办法.用了桥接模式之后,我们需要创建两套独立的"类体系"(class hierarchy):"抽象体系"定义了我们所要执行的操作(比如接口或高层算法