Java设计模式之——外观模式

外观模式的简单介绍

外观模式在开发过程中的运用频率非常高,尤其是在现阶段各种第三方 SDK 充斥在我们的周边,而这些 SDK 很大概率会使用外观模式。通过一个外观类使得整个系统的接口只有一个统一的高层接口,这样能够降低用户的使用成本,也对用户屏蔽了很多实现细节。当然,在我们的开发过程中,外观模式也是我们封装 API 的常用手段,例如网络模块、ImageLoader 模块等。可能你已经在开发中运用过无数次外观模式,只是没有在理论层面认识它,下面我们就从理论结合实践的角度学习这个模式。

外观模式定义

要求一个子系统的外部与其内部的通信必须通过一个统一的对象进行。门面模式提供一个高层次的接口,使得子系统更易于使用。

外观模式的使用场景

  • (1)为一个复杂子系统提供一个简单接口。子系统往往因为不断演化而变得越来越复杂,甚至可能被替换。大多数模式使用时都会产生更多、更小的类,在这是子系统更具可重用性的同时也更容易被子系统进行定制、修改,这种易变性使得隐藏子系统的具体实现变得尤为重要。外观模式可以提供一个简单统一的接口,对外隐藏子系统的具体实现、隔离变化;
  • (2)当你需要构建一个层次结构的子系统时,使用外观模式定义子系统中每层的入口点。如果子系统之间是相互依赖的,你可以让它们仅通过 外观模式提供的接口进行通信,从而简化了它们之间的依赖关系。

外观模式的 UML 类图

这里写图片描述

角色 介绍:

  • Facade:系统对外的统一接口,系统内部系统地工作。
  • SystemA、SystemB、SystemC:子系统接口

外观模式接口比较简单,就是通过一个统一的接口对外界提供服务,使得外部程序只通过一个类就可以实现系统内部的多种功能,而这些实现功能的内部子系统之间可能也有交互,或者说完成一个功能需要几个子系统之间进行协作,如果没有封装,那么用户就需要操作几个子系统的交互逻辑,容易出现错误。而通过外观类来对外屏蔽这些复杂的交互,可以降低用户的使用成本。

外观模式实战

生活中使用外观模式的例子非常多,任何一个类似中央调度结构的组织都类似外观模式,举个简单的例子,手机就是一个外观模式的例子,它集合了电话功能、短信功能、GPS、拍照于一身,通过手机你就可以完成各种功能。而不是当你打电话时使用一个 诺基亚 1100,要拍照时非得用一个相机,如果是这样每使用一个功能你就必须操作特定的设备,会使得整个过程很繁琐。而手机给了你一个统一的入口,集电话、上网、拍照等功能于一身,使用方便,操作简单。

下面我们来简单模拟一下手机的外观模式实现,首先我们建立一个 MobilePhone 类,代码大致如下:

public class MobilePhone {
    private Phone mPhone = new PhoneImpl();
    private Camera mCamera = new SamsungCamera();

    public void dail(){
        mPhone.dail();
    }

    public void videoChat(){
        //视频聊天
        mCamera.open();
        mPhone.dail();
    }

    public void hangup(){
        mPhone.hangup();
    }

    public void takePicture(){
        mCamera.open();
        mCamera.takePicture();
    }

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

MobilePhone 类中含有两个子系统,也就是拨号系统和拍照系统,MobilePhone 将这两个系统封装起来,为用户提供一个统一的操作接口,也就是用户只需要通过 MobilePhone 这个类就可以操作打电话和拍照这两个功能。用户不需要知道有 Phone 这个接口以及它的实现类是 PhoneImpl,同样也不需要知道 Camera 相关的信息,通过 MobilePhone 就可以包揽一切。而在 MobilePhone 中也封装了两个子系统的交互,例如视频电话时需要先打开摄像头,然后在开始拨号,如何没有这一步的封装,每次用户实现视频通过功能时都需要手动打开摄像头、进行拨号,这样会增加用户的使用成本,外观模式使得这些操作更加简单、易用。

我们来看看 Phone 接口 和 PhoneImpl。

public interface Phone {
    /**
     * 打电话
     */
     void dail();

    /**
     * 挂断
     */
    void hangup();
}

public class PhoneImpl implements Phone {
    @Override
    public void dail() {
        //打电话
    }

    @Override
    public void hangup() {
        //挂断
    }
}

代码很简单,就是单纯的抽象与实现。Camera 也是类似的实现,具体代码如下:

public interface Camera {
    /**
     * 打开相机
     */
    public void open();

    /**
     * 拍照
     */
    void takePicture();

    /**
     * 关闭相机
     */
    void close();
}

public class SamsungCamera implements Camera {
    @Override
    public void open() {
        //打开相机
    }

    @Override
    public void takePicture() {
        //拍照
    }

    @Override
    public void close() {
        //关闭相机
    }
}

测试代码:

public class Test {
    public static void main() {
        MobilePhone mobilePhone = new MobilePhone();
        //拍照
        mobilePhone.takePicture();
        //视频聊天
        mobilePhone.videoChat();
    }
}

从上述的代码中可以看到,外观模式就是统一接口封装。将子系统的逻辑、交互隐藏起来,为用户提供一个高层次的接口,使得系统更加易用,同时也对外隐藏了具体的实现,这样即使具体的子系统发生了变化,用户也不会感知到,因为用户使用的是外观模式的高层接口,内部的变化对于用户来说并不可见。这样一来就将变化隔离开来,是系统也更为灵活。

总结

外观模式是一个高频率使用的设计模式,它的精髓就在于封装二字。通过一个高层次结构为用户提供统一的 API 入口,使得用户通过一个类型就基本能够操作整个系统,这样减少了用户的使用成本,也能够提升系统的灵活性。

优点:

  • (1)对客户程序隐藏了子系统细节,因而减少了客户对于子系统的耦合,能够拥抱变化。
  • (2)外观类对子系统的接口封装,使得系统更易于使用。

缺点:

  • (1)外观类接口膨胀,由于子系统的接口都有外观类统一对外暴露,使得外观类的 API 接口较多,在一定程度上增加了用户使用成本。
  • (2)外观类没有遵循开闭原则,当业务出现变更时,可能需要直接修改外观类。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值