zoukankan      html  css  js  c++  java
  • 设计模式学习之Facade模式

     今天讲外观模式,这个模式其实理解起来超级简单,为什么呢?这个模式其实我觉得可以用四个字来形容它:化繁为简。因为这个模式就是用来提供简化接口的。什么是简化接口?其实就是将很多复杂的接口组合起来成为一个新接口。你或许会问,把许多复杂的接口组合起来不是会更复杂吗,怎么会变得简单,这不是自相矛盾吗?哈哈,那你就错了,其实外观模式更像一个东西:宏。又拿宏说事儿了,不是上次命令模式里面提到过“命令宏”的吗,这个模式和宏有什么关系呢?嘿嘿,如果把上次“命令宏”称为“狭义的宏”的话,那么外观模式就是“广义的宏”(似乎越来越难理解了……)。

           别急,让我慢慢道来,先解决为什么叫“广义的宏”这个问题。首先,广义代表这个模式具有很高的通用性,也就是说,它不只是限于对单一类型的接口进行“捆绑销售”,它还能对不同类型的接口进行“集中甩卖”,哎,说的专业点,就是外观模式可以将不同子系统的接口组合成一个接口供用户使用,而这个接口因为组合了很多的功能,使得用户不用自己去定义n多的子系统,然后自己手动操作这些子系统的方法,而只需要调用这个合成的接口就能完成一大堆的功能,是不是简化了呢?

           再来详细讲一下吧,定义还是必须的:

    • 外观模式: 
      为子系统中的一组接口提供一个一致的界面,Facade模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
    • 适用性:
    1. 当你要为一个复杂子系统提供一个简单接口时。子系统往往因为不断演化而变得越来越复杂。大多数模式使用时都会产生更多更小的类。这使得子系统更具可重用性,也更容易对子系统进行定制,但这也给那些不需要定制子系统的用户带来一些使用上的困难。Facade 可以提供一个简单的缺省视图,这一视图对大多数用户来说已经足够,而那些需要更多的可定制性的用户可以越过facade层。
    2. 客户程序与抽象类的实现部分之间存在着很大的依赖性。引入facade将这个子系统与客户以及其他的子系统分离,可以提高子系统的独立性和可移植性。
    3. 当你需要构建一个层次结构的子系统时,使用facade模式定义子系统中每层的入口点。如果子系统之间是相互依赖的,你可以让它们仅通过facade进行通讯,从而简化了它们之间的依赖关系。

    再上类图:

    外观模式类图

           对这类图是不是有点无语?是不是感觉摸不着头脑?呵呵,别被它的外表所吓倒,其实你只需要关心最上面的那个接口就行了,对于subsystem也就是子系统可以完全不需要仔细的考虑,而只需要知道如何调用子系统提供的接口就行了,我们还是用个例子来说吧:

           就拿开车来说,开车是需要很多的操作的,很多小细节啊(这可是学驾照时的亲身体会啊),我们简单说一下:开车门->插钥匙->启动发动机->踩离合器->进档->松离合器->松手刹->加油门->转动方向盘...(车跑起来了,哈哈,不过后序步骤就要靠你自己了;))。但随着科技的发展,现在果断出现了全自动的汽车(科技真给力),对于这种全自动的汽车来说,显然没有了人,这些操作就只能又计算机控制了,如果现在要你写一个这样的全自动驾车的程序,使得用户只需要插入钥匙,点击开车按钮就能自动开车了(这就方便了,每个人都会),那该怎么写呢?

           是不是觉得很复杂?没关系,让复杂的问题交给科学家吧,咱们要懂得利用他们的成果,嘻嘻,假设科学家们已经将复杂的控制功能封装好了,成为了一个个子系统,比如车门,档位,发动机,离合器,手刹,油门都有了各自的控制方法,那我们现在就只需要写汽车的接口,就三个:权限认证(插钥匙,当然现在科技这么发达,也有可能出现别的验证方式呢),还有开车,停车,怎么做呢:

    复制代码
    //汽车的接口
    public interface ICar
    {
        public bool auth();
        public void drive();
        public void stop();
    }
    复制代码

    如前所述,现在科学家提供了很多的控制类接口:

    复制代码
    //车门接口
    public interface ICarDoor
    {
        public void open();
        public void close();
    }
    //档位接口
    public interface IGears
    {
        public void setLevel(int level);
    }
    //转向灯接口
    public interface ITurnLight
    {
        //0为左,1为右
        public void setLight(int direction);
    }
    //喇叭接口
    public interface ISpeaker
    {
        public void beep();
    }
    //引擎接口
    public interface IEngine
    {
        public void open();
        public void close();
        public void refuel();
    }
    //离合器接口
    public interface IClutch
    {
        public void press();
        public void loose();
    }
    //手刹接口
    public interface IHandBrake
    {
        public void pull();
        public void loose();
    }
    //油门接口
    public interface IAccelerator
    {
        public void accelerate(int level);
    }
    //方向盘
    public interface IWheel
    {
        public void toLeft(int degree);
        public void toRight(int degree);
    }
    //权限认证(插钥匙,当然现在科技这么发达,也有可能出现别的验证方式呢),
    public interface IAuthSystem
    {
        public bool auth();
    }
    复制代码

    既然已经有了这么多接口,那么我们的自动系统就只需要根据这些接口进行顺序的调用就可以了:

    复制代码
    public class AutoCar implements ICar
    {
        ICarDoor carDoor;
        IGears gears;
        ITurnLight turnLight;
        ISpeaker speaker;
        IEngine engine;
        IClutch clutch;
        IHandBrake handBrake;
        IAccelerator accelerator;
        IWheel wheel;
        public AutoCar(ICarDoor carDoor, IGears gears,  ITurnLight turnLight, ISpeaker speaker, IEngine engine, 
        IClutch clutch, IHandBrake handBrake, IAccelerator accelerator, IWheel wheel, IAuthSystem authSystem)
        {
            this.carDoor=carDoor;
            this.gears=gears;
            this.turnLight=turnLight;
            this.speaker=speaker;
            this.engine=engine;
            this.clutch=clutch;
            this.handBrake=handBrake;
            this.accelerator=accelerator;
            this.wheel=wheel;
            this.authSystem=authSystem;
        }
        public void drive()
        {
            carDoor.close();//关门都由系统来做,人真懒啊,:)
            if(authSystem.auth())//验证权限
            {
                engine.open();//打开发动机
                clutch.press();//踩死离合器
                gears.setLevel(1);//进1档
                turnLight.setLight(0);//开左转向灯
                speaker.beep();//鸣笛
                clutch.loose();//松开离合器
                handBrake.loose();//松手刹
                accelerator.accelerate(1);//加一点就行了,别过猛了,不然会很暴力的,:)
                //后面的事交给科学家吧,:)
            }
        }
        public void stop();
    }
    复制代码

           这样一来,用户只需要关心ICar接口就行了,想想当你想出门的时候,只需要打开车门,插入钥匙,然后按“开车”按钮,然后什么都不用管,那将是多么的惬意啊,其实,这一切都得感谢外观模式啊,外观模式就是提供一个非常友好的外观给用户(长得漂亮谁不喜欢啊:)),使得用户不需要关心它内部的实现细节,使用户从繁重的工作中解脱出来。

           唉,这上面就是外观模式?不就是把一堆类集合在一起,然后把需要的不同类的方法集中到一个方法里面实现吗,这么简单?是啊,就这么简单!多简单啊!我想现在你应该搞清楚为什么我把外观模式叫做广义的宏了吧,不信你再看看上面的代码,Car类中的drive()方法不就是个典型的宏吗,如果你还不清楚,请深入的学一下office word,:)

           好了,这个模式就讲到这里,但顺便提一下另外几个模式:装饰者模式和适配器模式,难道这三个模式有什么共同点吗?是的,它们的共同点就是:对接口进行再次封装。装饰者模式是将被装饰者的接口动态的加上新的职责,适配器模式是将被适配者的接口转换成新的接口,而外观模式则是组合多个系统的接口创造新的接口。各种模式都有各自独特的作用,要看你怎么用了。

     
    分类: 软件设计

    软件设计

     
    摘要: 今天讲外观模式,这个模式其实理解起来超级简单,为什么呢?这个模式其实我觉得可以用四个字来形容它:化繁为简。因为这个模式就是用来提供简化接口的。什么是简化接口?其实就是将很多复杂的接口组合起来成为一个新接口。你或许会问,把许多复杂的接口组合起来不是会更复杂吗,怎么会变得简单,这不是自相矛盾吗?哈哈,那你就错了,其实外观模式更像一个东西:宏。又拿宏说事儿了,不是上次命令模式里面提到过“命令宏”的吗,这个模式和宏有什么关系呢?嘿嘿,如果把上次“命令宏”称为“狭义的宏”的话,那么外观模式就是“广义的宏”(似乎越来越难理解了……)。 别急,让我慢慢道来,先解决为什么叫“广义的宏”这个问题。首先,广义代.阅读全文
    posted @ 2012-08-03 09:08 everdom 阅读(446) | 评论 (3) 编辑
    摘要: 今天要说适配器模式了,适配器模式其实非常好理解,因为现实中存在很多不同种类的适配器,像usb转串口线就是讲usb接口和串口进行转换,VGA转HDMI线就是讲VGA接口和HDMI接口进行转换,这些都是硬件层次的,那么软件层次的就更好举例了,比如现在有某些usb设备,像usb无线键盘/鼠标啊,usb网卡等等如果直接插到电脑上是不会工作的,必须在电脑端还要装上相应的驱动程序,那么这个驱动程序其实就是一个软件适配器,将usb设备转换成为操作系统能够识别的设备,其实,usb设备远不止这些,到淘宝一查,我来个去,真是什么都有啊: 其实这些设备不是都有适配器的,有很多只用使用usb进行供电,把usb当电..阅读全文
    posted @ 2012-07-31 19:52 everdom 阅读(41) | 评论 (0) 编辑
    摘要: 今天学习了命令模式,这个模式非常的给力,它能将命令封装起来让另外的执行者去执行,相当于一个命令的收集和转发过程,而且,这个模式还能将一系列的命令组合成“命令宏”,并且可以轻松的完成撤销的操作,非常适合日志系统或事务处理系统,也常用于窗口编程中的菜单命令处理,好了,下面回顾一下这个模式吧命令模式: 将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤消的操作。 适用性:抽象出待执行的动作以参数化某对象,你可用过程语言中的回调(callback)函数表达这种参数化机制。所谓回调函数是指函数先在某处注册,而它将在稍后某个需要的时候被调用。Comma阅读全文
    posted @ 2012-07-31 11:43 everdom 阅读(47) | 评论 (0) 编辑
    摘要: 终于到了工厂模式了,说起工厂模式,不得不把工厂方法模式和抽象工厂模式结合起来说,这两种模式都有工厂,乍听起来还真容易混淆,但它们却是不相同的两种模式,但又互相有联系。那么这两者之间各有什么用途,互相之间又有什么联系呢?一个一个来吧。既然说起了工厂模式,那么首先有一点是需要搞清的,那就是,所有的工厂模式都是为了将对象的创建过程封装起来,要么将创建过程隔离出来,要么将创建过程抽象成接口。那么,在说这两种模式之前,先说一下简单工厂,所谓的简单工厂,其实就是一种最简单的将创建过程隔离的设计方法。我们通常在创建一个对象时,都会用到如下语句:Object o=new Object();即new一个对象,但阅读全文
    posted @ 2012-07-27 11:36 everdom 阅读(106) | 评论 (0) 编辑
    摘要: 继续学习设计模式,今天是装饰者模式,它属于结构型模式,首先还是它的基本概念:装饰者模式:动态地给一个对象添加一些额外的职责。就增加功能来说,Decorator模式相比生成子类更为灵活。 适用性:在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。处理那些可以撤消的职责。当不能采用生成子类的方法进行扩充时。一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。另一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类。 我的理解是:装饰者模式就好比一个个wrapper(包装器),将一个对象一层层的包装,然后返回包装后的对象,就好比你在网上购买了阅读全文
    posted @ 2012-07-25 09:27 everdom 阅读(25) | 评论 (0) 编辑
    摘要: 今天继续学习设计模式。学到的两个模式:观察者模式,它属于行为性模式。观察者模式:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时, 所有依赖于它的对象都得到通知并被自动更新。适用性:当一个抽象模型有两个方面, 其中一个方面依赖于另一方面。将这二者封装在独立的对象中以使它们可以各自独立地改变和复用。当对一个对象的改变需要同时改变其它对象, 而不知道具体有多少对象有待改变。当一个对象必须通知其它对象,而它又不能假定其它对象是谁。换言之, 你不希望这些对象是紧密耦合的。我的理解是:观察者模式首先定义了一个被观察者,然后让很多的观察者订阅被观察者,而被观察者在自己的状态有了更新时向所有的观阅读全文
    posted @ 2012-07-25 09:22 everdom 阅读(11) | 评论 (0) 编辑
     
     
  • 相关阅读:
    Java:类加载器(ClassLoader)
    Java 并发:Executor
    Java 并发:线程中断-interrupt
    UNIX IPC: POSIX 消息队列 与 信号
    Java与C++区别:重载(Overloading)
    UNIX IPC: POSIX 消息队列
    PAT 1078. Hashing
    PAT 1032. Sharing
    回顾经典问题算法:LIS, LCS-(DP类别)
    url编码模块
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/2621621.html
Copyright © 2011-2022 走看看