外观模式--做一个低调的人

1)概述
外观模式提供了一个统一的接口去访问多个子系统的多个不同的接口。定义一个高层次的接口,使得子系统更加容易被使用。
外观模式提供了一个简单而且公用的接口去处理复杂的子系统,并且没有减少子系统的功能。它遮蔽了子系统的复杂性,避免了客户与子系统直接连接,它减少了子系统与子系统之间的连接,每一个子系统都有它的Facade模式,每个子系统采用Facade模式去访问其他的子系统。外观模式的缺点是限制了客户的自由,减少了可变性。

2)提出问题
家兴,是一个非常喜欢打2K(模仿NBA比赛的游戏),相当于音乐发烧友那样子,这个月刚发工资,就拿工资去买了一对游戏手柄,和一台较大的显示屏,和一个音响,还买了一个爆米花机(他喜欢游戏吃爆米花)。这些电子设备刚买回来,家兴马上兴致勃勃去装好这些设备,好不容易才装好这些设备。坐在沙发上,准备开始。。。。。
家兴头痛了,还有做很多工作:
1.打开爆米花机
2.开始爆米花
3.打开电脑,启动游戏
4.打开游戏手柄
5.将显示屏设置电脑输入
6.打开音响
7.将功放设置为环绕立体声
8.调节音响的声音适中
这只是开始。。。。
还有结束的工作呢。。
如何去解决这样的问题呢?

3)解决方案
通过使用外观模式,我们可以创建一个接口简化而统一的接口,用来包装子系统中一个或多个复杂的类。允许我们让客户端和子系统之间避免紧耦合,也可以让我们满足一个新的面向对象。
我们通过原来繁琐或复杂的过程变得更加简单,但是呢同时不会对子系统造成什么影响的。

4)使用场合
1.在设计初期阶段,应该要有意识的将不同的两个层分离,比如经典的三层架构,就需要考虑在数据访问层和业务逻辑层和表示层的层与层之间建立Facade,这样就可以为复杂的子系统提供一个简单的接口,是的耦合大大减低。
2.在开发阶段,子系统往往因为不断的重构演化而变得越来越复杂,大多数的模式使用时也都会产生很多很小的类,这本是好事,但也给外部调用他们的用户程序带来了使用上的困难,增加外观Facade可以提供一个简单的接口,减少它们之间的依赖。
3.在维护一个遗留的大型系统时,可能这个系统已经很难维护和扩展,但因为它包含非常重要功能,新的需求开发必须要依赖于它。此时使用外观模式Facade也是非常合适。你可以为新系统开发一个外观Facade类,来提供设计粗糙或高度复杂的遗留代码的比较简单的接口,让新系统与Facade交互,Facade与遗留代码加护所有复杂的工作。

5)结构
Client:客户端类,对Facade类进行调用,进行开始玩游戏和不玩游戏行为
Facade:外观类,外观模式的核心;对各种子系统的功能使用,来实现各种繁琐,复杂的行为的效果,减少操作,屏蔽子系统。
Popcorn:爆米花机类,主要实现爆米花各种行为。
Computer:电脑类,实现游戏的相关操作。
Gamepad:游戏手柄类,启动游戏手柄,开始游戏手柄操作。
DisplayScreen:显示屏,开显示屏,调节为电脑信号输入等操作。
Acoustics:音响类,开启音响,调节音响的音量

6)外观模式XML图
这里写图片描述

7)代码实现

//客户端类
public class Client {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        //家兴要玩2K游戏了
        Facade facade = new Facade();
        facade.playStart();

        //家兴不玩游戏了
        facade.playOff();

    }

}

//外观类
public class Facade {
    private Popcorn popcorn;
    private Computer computer;
    private Gamepad gamepad;
    private DisplayScreen displayScreen;
    private Acoustics acoustics;

    public Facade(){
        popcorn = new Popcorn();
        computer = new Computer();;
        acoustics = new Acoustics();
        gamepad = new Gamepad();
        displayScreen = new DisplayScreen();
    }

    public void playStart(){
        this.popcorn.palyOn();
        this.popcorn.palyStart();

        this.computer.playOn();
        this.computer.playStart();

        this.gamepad.playOn();
        this.gamepad.playStart();

        this.displayScreen.getOn();
        this.displayScreen.playStart();

        this.acoustics.getOn();
        this.acoustics.toning();
    }
    public void playOff(){
        this.popcorn.playOff();

        this.computer.playEnd();
        this.computer.playOff();

        this.gamepad.playOff();

        this.displayScreen.getOff();

        this.acoustics.getOff();
    }

}

//爆米花类
public class Popcorn {
    public void palyOn(){
        System.out.println("爆米花机要开机了");
    }
    public void palyStart(){
        System.out.println("开始炸取爆米花\n");
    }
    public void playOff(){
        System.out.println("要关掉爆米花机了\n");
    }public class Computer {
    public void playOn(){
        System.out.println("要开电脑了");
    }
    public void playStart(){
        System.out.println("启动电脑软件2K2016,请准备玩游戏\n");
    }
    public void playEnd(){
        System.out.println("要关闭软件2K2016了,请注意");
    }
    public void playOff(){
        System.out.println("要关闭电脑了\n");
    }

}

}

//电脑类
public class Computer {
    public void playOn(){
        System.out.println("要开电脑了");
    }
    public void playStart(){
        System.out.println("启动电脑软件2K2016,请准备玩游戏\n");
    }
    public void playEnd(){
        System.out.println("要关闭软件2K2016了,请注意");
    }
    public void playOff(){
        System.out.println("要关闭电脑了\n");
    }

}

//游戏手柄类
public class Gamepad {
    public void playOn(){
        System.out.println("开启游戏手柄!");
    }
    public void playStart(){
        System.out.println("开始游戏操作!\n");
    }
    public void playOff(){
        System.out.println("关闭游戏手柄!\n");
    }

}

//显示屏类
public class DisplayScreen {
    public void getOn(){
        System.out.println("启动显示屏电源!进入开机状态!");
    }
    public void playStart(){
        System.out.println("进入调式进入电脑信号输入!\n");
    }
    public void getOff(){
        System.out.println("关闭显示屏电源,处于关机状态!\n");
    }
}

//音响类
    public void getOn(){
        System.out.println("开启音响设备!");
    }
    public void toning(){
        System.out.println("调节音响设备的音量适中!\n");
    }
    public void getOff(){
        System.out.println("关闭音响设备!\n");
    }

}

程序执行结果:
爆米花机要开机了
开始炸取爆米花

要开电脑了
启动电脑软件2K2016,请准备玩游戏

开启游戏手柄!
开始游戏操作!

启动显示屏电源!进入开机状态!
进入调式进入电脑信号输入!

开启音响设备!
调节音响设备的音量适中!
从结果显示,本来是一个很繁琐的行为,结果只是执行Facade类的一个行为就很轻易的实现了,客户端不需要知道什么的子系统,只需要调用一下就能实现。

8)适配器和外观模式之间的差异在于:适配器包装一个类,而外观模式可以代表许多类?
适配器模式是讲一个或多个类接口变成客户所期望的一个接口。虽然大多数教科书多采用的例子适配器一个类,但是你可以适配许多类类提供一个接口让客户编码。同样的,一个外观模式也可以针对一个拥有复杂接口的类提供简化接口。两种模式的差异在于,不在于他们包装几个类,而是在于他们的目的。适配器是改变接口符合客户的使用,而外观模式只是把接口变得更加简单,并没有改变。

9)最少知识原则
最少知识原则告诉我们要减少对象之间的交互,只留下几个密友;只和你的密友交谈。
优点:不要让太多的类耦合在一起,免得修改系统中一部分,会影响其它部分,免得修改系统中一部分,会影响到其他部分。如果许多类之间相互依赖,那么这个系统就会变成一个易碎的程序,它需要很多成本维护,也会因为复杂不被别人了解。
缺点:是的,虽然这个原则减少对象之间的依赖,研究显示这会减少软件之间的维护成本;但是呢采用这个原则也会导致更多包装类被制造出来,以处理和其他组件的沟通,这可能会导致复杂度和开发时间增加,并减低运行时的效率。

10)最少知识原则和外观模式
如果一个客户端一个朋友(一个Facade),这个朋友帮助客户管理所有子系统组件,它的存在让客户变得简单又有弹性。
我们可以在不影响客户端的情况下对子系统进行更新或维护等;
我们也可以试着让子系统也能符合最少原则,如果变得复杂,有太多的朋友牵涉其中,那么我们可以增加更多的外观,将次系统分成几个层次。

11)综合模式
外观模式与单例模式: 在外观模式中,通常只需要一个外观类,并且此外观类只有一个实例,换言之它是一个单例类。在很多情况下为了节约系统资源,一般将外观类设计为单例类。当然这并不意味着在整个系统里只能有一个外观类,在一个系统中可以设计多个外观类,每个外观类都负责和一些特定的子系统交互,向用户提供相应的业务功能。
不要试图通过外观类为子系统增加新行为:
外观模式与最少知识原则:外观模式创造出一个外观对象,将客户端所涉及的属于一个子系统的协作伙伴的数量减到最少,使得客户端与子系统内部的对象的相互作用被外观对象所取代。外观类充当了客户类与子系统类之间的“第三者”,降低了客户类与子系统类之间的耦合度,外观模式就是实现代码重构以便达到最少知识原则要求的一个强有力的武器。
抽象模式与外观模式:外观模式最大的缺点在于违背了“开闭原则”,当增加新的子系统或者移除子系统时需要修改外观类,可以通过引入抽象外观类在一定程度上解决该问题,客户端针对抽象外观类进行编程。对于新的业务需求,不修改原有外观类,而对应增加一个新的具体外观类,由新的具体外观类来关联新的子系统对象,同时通过修改配置文件来达到不修改源代码并更换外观类的目的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值