外观模式(facadePattern)又叫门面模式,隐藏了子系统的复杂实现,为子系统中的一组接口提供了一个统一的访问入口,使得子系统容易被访问或使用,说白了就是把复杂的子系统封装成一个接口供给外部用户更简单地使用,这也是一种结构型模式。
模式结构图:
此模式中涉及的三种角色:
1、门面角色(Facade):外观模式的核心,被客户端调用,它知道子系统的功能,内部根据客户端角色的需求制定了几种功能组合,通过聚合的方式,持有了子系统的引用;
2、子系统角色:实现了子系统的功能,它对客户端角色和门面角色是未知的,其内部既可以有系统内的相互交互,也可以有共外界调用的接口;
3、客户端角色:通过调用Facade来完成要实现的功能;
模式举例:假如我们买了一台车,但是光买完还不够,我们还要交车船税、上车牌、买保险,之后我们才可以上路行驶,可是我们嫌这些流程太繁琐,正好4S店说可以代办这些业务,我们就可以将这些事情委托给4S店代办,这种场景我们就可以将4S店销售人员抽象为门面角色,将缴税、上车牌、买保险抽象为子系统的角色,我们自然就是客户端角色了。
示例代码如下:
package cn.com.wwh.model.facade; /** * * @version: 1.0 * @Description: 税务子系统 * @author: wwh * @date: 2022年9月22日-下午8:05:28 */ public class Tax { private static final Tax INSTANCE = new Tax(); public static Tax getInstance() { return INSTANCE; } public void write() { System.err.println("填写资料..."); } public void pay() { System.err.println("缴税..."); } public void getInvoice() { System.err.println("获取发票..."); } }
package cn.com.wwh.model.facade; /** * * @version: 1.0 * @Description: 选号子系统 * @author: wwh * @date: 2022年9月22日-下午7:56:38 */ public class License { private static final License INSTANCE = new License(); public static License getInstance() { return INSTANCE; } public void pay() { System.err.println("缴费..."); } public void check() { System.err.println("验车..."); } public void getLicense() { System.err.println("上牌结束..."); } }
package cn.com.wwh.model.facade; /** * * @version: 1.0 * @Description: 保险子系统 * @author: wwh * @date: 2022年9月22日-下午7:57:56 */ public class Insurance { private static final Insurance INSTANCE = new Insurance(); public static Insurance getInstance() { return INSTANCE; } public void write() { System.err.println("填写参保信息..."); } public void pay() { System.err.println("交钱成功..."); } public void success() { System.err.println("参保成功..."); } }
package cn.com.wwh.model.facade; /** * * @version: 1.0 * @Description: 销售人员充当外观类角色,通过聚合的方式持有子系统的引用 * @author: wwh * @date: 2022年9月22日-下午8:12:06 */ public class Saleman { private License license; private Tax payTax; private Insurance insurance; public Saleman() { license = License.getInstance(); payTax = Tax.getInstance(); insurance = Insurance.getInstance(); } // 调起税务子系统 public void invokePayTax() { payTax.write(); payTax.pay(); payTax.getInvoice(); } // 调起选号子系统 public void invokeLicense() { license.pay(); license.check(); license.getLicense(); } //调起保险子系统 public void invokeInsurance() { insurance.write(); insurance.pay(); insurance.success(); } }
package cn.com.wwh.model.facade; /** * * @version: 1.0 * @Description: 客户端角色 * @author: wwh * @date: 2022年9月22日-下午8:21:25 */ public class Cluster { public static void main(String[] args) { Saleman saleman = new Saleman(); saleman.invokePayTax(); saleman.invokeLicense(); saleman.invokeInsurance(); } }
UML类图:
使用场景:
1、为复杂的模块或子系统提供外界访问的模块;
2、子系统相互独立;
3、在层析结构中,可以使用外观模式定义每一层的入口,我们常使用的MVC模式也算是一种外观模式;
优点:
1、松散耦合,使得客户端和子系统之间解耦,让子系统内部的功能模块更容易扩展和维护;
2、简单易用,客户端根本不需要知道子系统的内部实现,或者根本不需要知道子系统的存在,只需要与外观类facade交互即可;
3、更好的划分层次访问,有些方法是对外的,有些方法是对内的,使用外面模式可以隐藏这些细节,或者说控制一些方法的访问;
缺点:
1、不符合开闭原则,如果要改东西很麻烦,继承重写都不合适;
2、所有的逻辑都依赖门面类,这个类出问题的话可能会影响整个系统;
总的来说,外观模式的本质是:封装交互,简化调用。让复杂的步骤封装起来,让使用者调用更见简单,减少与子系统的交互。
好了,今天的介绍就到这,还请各位大佬批评指正,谢谢。