牛骨文教育服务平台(让学习变的简单)

终于考试完了,瞬间感觉轻松了许多,又可以安心地写代码了,下面进入今天的正题–外观模式。
外观模式,也称门面模式,顾名思义,就是一个对象封装了一系列相关的操作(行为),使得这些操作仅对外提供(暴露)方法(接口),客户端根据这些外观(暴露的接口)就可以简单地完成一系列操作,达到了客户端无需知道内部实现细节,只需知道对象的外观就可以实现一系列行为,简单来说就是面向对象的封装。这一系列行为也就是一个系统的功能。

定义:通过一个统一的对象实现一个系统的外部与内部的通讯,提供了一个高层次的接口,使得系统功能更加透明,更加容易使用。

使用场景:

  1. 为一个复杂系统提供一个简单的接口。为一个复杂系统提供一个简单的接口,对外部隐藏系统的内部实现,隔离变化,使得当这个系统因为不断演化而不断的修改,定制也可以更加容易地扩展使用,即对外部的使用是一样的,客户端无需知道内部发生了什么变化,隐藏了系统的内部实现,这也就是封装的好处了。

  2. 简化子系统之间的依赖,降低它们之前的耦合。当不同的子系统需要使用其他系统的功能的时候,那么我们就需要构建一个层次结构的系统,这时我们通过外观模式为这些子系统提供一个通讯接口,即每层的入口点。

优点:

  1. 因为对客户端隐藏了系统的细节,减少了客户端对于系统的耦合,能够拥抱变化。

  2. 对系统一系列功能进行了整合,封装,使得系统更加容易使用。

缺点:

  1. 外观类接口膨胀。因为我们外观类需要封装一系列相关的功能,这一系列相关的功能可能需要不同的类实现,那么我们不是简单地给这个外观类提供实现不同功能类,而是为每个实现不同功能的类提供一个接口,然后再使用的时候给这些接口提供实现类,这样可以便于扩展,反之,外观类接口必然膨胀,也增加了程序员的一定的负担。

  2. 违背了开闭原则,当业务出现变更的时候,可能需要直接修改外观类(通常是修改外观类中的接口的实现类)。

下面以现代智能机模拟实现外观模式

代码实现:

虚拟手机(接口)—-接打电话功能接口

public interface Phone {
    /**
     * 打电话
     */
    public void call();
    /**
     * 挂断
     */
    public void handup();
}

虚拟相机(接口)—-拍照功能接口

/**
 * 照相机
 * @author lt
 *
 */
public interface Camera {
    public void open();
    public void takePicture();
    public void close();
}

真实的手机(实现类)

/**
 * 以前的旧手机,非智能,只能打电话和挂电话
 * @author lt
 *
 */
public class PhoneImpl implements Phone{

    @Override
    public void call() {
        System.out.println("打电话");
    }

    @Override
    public void handup() {
        System.out.println("挂断电话");
    }
}

真实的相机(实现类)

/**
 * 三星相机
 * @author lt
 *
 */
public class SamsungCamera implements Camera{

    @Override
    public void open() {
        System.out.println("打开相机");
    }

    @Override
    public void takePicture() {
        System.out.println("拍到了一个美女");
    }

    @Override
    public void close() {
        System.out.println("相机关闭了");
    }
}

现代智能机(Android/Iphone)—-外观类

/**
 * 现代智能机 ---  集照相,视频聊天,打电话于一身
 * @author lt
 * 
 */
public class SmartPhone {
    // 对应实现完成手机功能接口的实现类
    public Phone phone = new PhoneImpl();
    // 对应实现相机功能接口的实现类
    public Camera camera = new SamsungCamera();

    public void call() {
        phone.call();
    }

    public void hangup() {
        phone.handup();
    }

    public void takePicture() {
        openCamera();
        camera.takePicture();
        closeCamera();
    }

    public void openCamera() {
        camera.open();
    }

    public void closeCamera() {
        camera.close();
    }

    /**
     * 视频通话
     */
    public void videoChat() {
        openCamera();
        System.out.println("和妹子视频聊天");
        closeCamera();
    }
}

SmartPhone是外观类,这里具体是现代智能机,具有接打电话,拍照等功能,是这个模式核心类;Phone和Camera是两个特定功能的接口,分别是接打电话的功能,拍照功能,相应的实现类是PhoneIml和SamsungCamera。这里给外观类整了两个接口,即Phone和Camera,这样做的目的是以后要修改接打电话和拍照功能的实现时(如新的硬件)只需要将外观类SmartPhone中的相应功能的接口实现类改变一下就可以了,其他的都不用改,这也就是面向接口编程的好处,和J2EE中的Service,Dao层都提供一个接口和相应实现类一样,目的是一样的,即便于修改扩展。

测试:

public class Test {

    public static void main(String[] args) {
        SmartPhone iphone7s = new SmartPhone();
        // 用7s拍照
        iphone7s.takePicture();
        // 用7s视频聊天
        iphone7s.videoChat();
    }
}

运行结果:

这里写图片描述

可以看到,现代的智能机既有一般手机的功能,也有相机的功能,使得我们只需要一部智能机就不需要专门为打电话买一个手机,专门为拍照买一个相机了,一部手机统统搞定,而且避免了许多麻烦,如我们点击屏幕的相机(系统内置App)系统自动打开了相机,拍照完了以后系统自动将相机关闭,视频聊天也一样,这使得我们使用更加简单,更加方便。

总结:

外观模式使用也非常多,面向对象中的封装也通常是使用了外观模式,封装不一定使用了外观模式,但外观模式一定需要封装。通过外观模式,使得复杂系统功能更加丰富,使用更加简单。通过一个外观类就可以操作整个系统,减少了用户的使用成本,同时因为内部面向接口编程,使得使扩展维护更加简单,从而使得系统可以容易地面对多变的场景,提升了系统的扩展性灵活性。