【设计模式】外观模式

天平山上白云泉,云自无心水自闲

先用两个图来表示一下外观模式产生的原因:
在这里插入图片描述
使用外观模式之后:
在这里插入图片描述
可以明显的看到,使用外观模式之后,就可以让外部减少与子系统内多个模块的交互,松散耦合,从而让外部能够更简单地使用子系统

外观模式(Facade Pattern):外部与一个子系统的通信必须通过一个 统一的外观对象 进行,为子系统中的一组接口 提供一个一致的界面外观模式定义了一个高层接口,这个接口 使得这一子系统更加容易使用 。外观模式又称为 门面模式 ,它是一种 对象结构型模式。

先来解释一下两个词:

  • 界面:这里提到的界面,主要指的是从一个组件外部来看这个组件,能够看到什么,这就是这个组件的界面,也就是所说的外观。
  • 接口:这里提到的接口,主要指的是外部和内部交互的一个通道,也就是客户端和被访问的系统之间的一个通道,并不只局限于我们平时所说的接口interface,还可以是方法。

模式结构:

  • Facade:外观角色: 定义子系统的多个模块对外的高层接口,通常需要调用内部多个模块,从而把客户的请求代理给适当的子系统对象。
  • Module:子系统角色:实现系统的部分功能,客户可以通过外观角色访问它,各个模块之间可能有交互。

For Example

场景:你考上了大学,开学了,觉得笔记本电脑打游戏不够拉风,准备在宿舍装一个台式电脑,你决定先自己试着装一下,于是要去电子市场里买CPU、主板、显示屏,但由于你对电脑一窍不通,自己组装虽然省钱,但属实麻烦,不如找一个安装电脑公司(外观),这样你只需要最后拿电脑就行了。

电子市场,里面有CPU、主板、显示屏:

package com.ekin.softwaredesign.facade;

/**
 * @Author: ekin
 * @Date: 2021/4/11 18:29
 */
public class Emarket {
    private String cpu;
    private String screen;
    private String mainBoard ;

    public Emarket() {
    }

    public Emarket(String cpu, String screen, String mainBoard) {
        this.cpu = cpu;
        this.screen = screen;
        this.mainBoard = mainBoard;
    }

    public String getCpu() {
        return cpu;
    }

    public void setCpu(String cpu) {
        this.cpu = cpu;
    }

    public String getScreen() {
        return screen;
    }

    public void setScreen(String screen) {
        this.screen = screen;
    }

    public String getMainBoard() {
        return mainBoard;
    }

    public void setMainBoard(String mainBoard) {
        this.mainBoard = mainBoard;
    }
}

安装CPU服务:

package com.ekin.softwaredesign.facade;

/**
 * @Author: ekin
 * @Date: 2021/4/11 18:33
 */
public class CpuService {
    public boolean installCpu(Emarket emarket){
        System.out.println("安装CPU服务");
        return true;
    }
}

安装显示屏服务:

package com.ekin.softwaredesign.facade;

/**
 * @Author: ekin
 * @Date: 2021/4/11 18:35
 */
public class ScreenService {
    public boolean installScreen(Emarket emarket){
        System.out.println("安装显示屏服务");
        return true;
    }
}

安装主板服务:

package com.ekin.softwaredesign.facade;

/**
 * @Author: ekin
 * @Date: 2021/4/11 18:36
 */
public class MainBoardService {
    public boolean installBoard(Emarket emarket){
        System.out.println("安装主板服务");
        return true;
    }
}

电脑组装公司(外观类):

package com.ekin.softwaredesign.facade;

/**
 * @Author: ekin
 * @Date: 2021/4/11 18:46
 */
public class ComputerCompany {
    private CpuService cpuService;
    private MainBoardService mainBoardService;
    private ScreenService screenService;

    public CpuService getCpuService() {
        return cpuService;
    }

    public void setCpuService(CpuService cpuService) {
        this.cpuService = cpuService;
    }

    public MainBoardService getMainBoardService() {
        return mainBoardService;
    }

    public void setMainBoardService(MainBoardService mainBoardService) {
        this.mainBoardService = mainBoardService;
    }

    public ScreenService getScreenService() {
        return screenService;
    }

    public void setScreenService(ScreenService screenService) {
        this.screenService = screenService;
    }

    public void computerCompany(Emarket emarket){
        if(CpuService.installCpu(emarket)){
            if (ScreenService.installScreen(emarket)) {
                if (MainBoardService.installBoard(emarket)) {
                    System.out.println("电脑组装完成,打游戏起飞~");
                }
            }
        }
    }
}

测试类:

package com.ekin.softwaredesign.facade;

/**
 * @Author: ekin
 * @Date: 2021/4/11 18:54
 */
public class Test {
    public static void main(String[] args) {
        Emarket emarket = new Emarket("cpu","screen","mainBoard");
        ComputerCompany computerCompany = new ComputerCompany();
        computerCompany.computerCompany(emarket);
    }
}

UML图:
在这里插入图片描述
只与外观类交互:

package com.ekin.softwaredesign.facade;

/**
 * @Author: ekin
 * @Date: 2021/4/11 18:46
 */
public class ComputerCompany {

    private CpuService cpuService = new CpuService();
    private MainBoardService mainBoardService = new MainBoardService();
    private ScreenService screenService = new ScreenService();


    public void computerCompany(Emarket emarket){
        if(CpuService.installCpu(emarket)){
            if(ScreenService.installScreen(emarket)){
                if (MainBoardService.installBoard(emarket)) {
                    System.out.println("电脑组装完成,打游戏起飞~");
                }
            }
        }
    }
}

UML:
在这里插入图片描述
调用顺序示意图:
在这里插入图片描述
总结

  • 可以看到外观模式的本质是封装交互,简化调用,外观封装了子系统外部和子系统内部多个模块的交互过程,从而简化了外部的调用。通过外观,子系统为外部提供一些高层的接口,以方便它们的使用
  • 体现了“最少知道原则”

优点:

  • 松散耦合:外观模式松散了客户端与子系统的耦合关系,让子系统内部的模块能更容易扩展和维护。
  • 简单易用:外观模式让子系统更加易用,客户端不再需要了解子系统内部的实现,也不需要跟众多子系统内部的模块进行交互,只需要跟外观交互就可以了,相当于外观类为外部客户端使用子系统提供了一站式服务。
  • 更好地划分访问的层次:通过合理使用Facade,可以帮助我们更好地划分访问的层次。有些方法是对系统外的,有些方法是系统内部使用的。把需要暴露给外部的功能集中到外观中,这样既方便客户端使用,也很好地隐藏了内部的细节

缺点:

  • 如果外观过多的话,将不知道是调用模块还是外观
  • 在不引入抽象外观类的情况下,增加新的子系统可能需要修改外观类或客户端的源代码,违背了“开闭原则”,如果想要解决这个问题可以改用抽象外观类,当有新的业务需求要添加的时候,可以对应增加一个新的具体外观类

?什么时候用外观:

  • 如果希望为一个复杂的子系统提供一个简单接口的时候,可以考虑使用外观模式。使用外观对象来实现大部分客户需要的功能,从而简化客户的使用
  • 如果想要让客户程序和抽象类的实现部分松散耦合,可以考虑使用外观模式,使用外观对象来将这个子系统与它的客户分离开来,从而提高子系统的独立性和可移植性。
  • 如果构建多层结构的系统,可以考虑使用外观模式,使用外观对象作为每层的入口,这样可以简化层间调用,也可以松散层次之间的依赖关系。
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值