外观模式(Facade Pattern)

发布时间 2023-05-22 15:51:29作者: 街酒

一、模式动机

外观模式(Facade Pattern)是一种使用频率非常高的设计模式,它通过引入一个外观角色来简化客户端和子系统之间的操作为复杂的子系统调用提供一个统一的入口,使子系统与客户端的耦合度降低,且客户端调用非常方便。
外观模式中,外部与一个子系统的通信可以通过一个统一的外观对象进行。外观模式又称为“门面模式”。也是对象结构型模式之一。

  • 一个客户类需要和多个业务类交互,有时候这些需要交互的业务类会作为一个整体出现
  • 引入一个新的外观类(Facade)来负责和多个业务类【子系统(Subsystem)】进行交互,而客户类只需与外观类交互
  • 为多个业务类的调用提供了一个统一的入口,简化了类与类之间的交互
    • 没有外观类:每个客户类需要和多个子系统之间进行复杂的交互,系统的耦合度将很大
    • 引入外观类:客户类只需要直接与外观类交互,客户类与子系统之间原有的复杂引用关系由外观类来实现,从而降低了系统的耦合度功能
      image

二、模式定义

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

三、模式结构

image

四、案例实现

案例背景

电源开关,可以控制电灯,风扇,空调和电视机的关闭

案例结构

image

代码实现

public class Light {

    private String position;

    public Light(String position) {
        this.position = position;
    }

    public void on(){
        System.out.println(this.position+"开灯");
    }
    public void off(){
        System.out.println(this.position+"关灯");
    }
}

电视

public class Television {

    public void on(){
        System.out.println("开电视");
    }
    public void off(){
        System.out.println("关电视");
    }

}

空调

public class AirConditioner {

    public void on(){
        System.out.println("开空调");
    }
    public void off(){
        System.out.println("关空调");
    }

}

风扇

public class Fan {

    public void on(){
        System.out.println("开风扇");
    }
    public void off(){
        System.out.println("关风扇");
    }

}

开关

public class SwitchFacade {

    private Light lights[] = new Light[4];
    private Fan fan;
    private AirConditioner airConditioner;
    private Television television;

    public SwitchFacade() {

        lights[0] = new Light("左前");
        lights[1] = new Light("左后");
        lights[2] = new Light("右前");
        lights[3] = new Light("右后");

        fan = new Fan();
        airConditioner = new AirConditioner();
        television = new Television();
    }

    public void on(){
        lights[0].on();
        lights[1].on();
        lights[2].on();
        lights[3].on();
        fan.on();
        airConditioner.on();
        television.on();
    }

    public void off(){
        lights[0].off();
        lights[1].off();
        lights[2].off();
        lights[3].off();
        fan.off();
        airConditioner.off();
        television.off();
    }
}

客户测试类

public class Client {

    public static void main(String[] args) {
        SwitchFacade switchFacade = new SwitchFacade();
        switchFacade.on();
        System.out.println("-------------------------------");
        switchFacade.off();
    }

}

运行结果

image

案例分析

开关类中关联子系统类,开关类中的方法是调用子系统的方法,如果要增加新的子系统,需要引进抽象外观类

五、模式分析

  • 是迪米特法则的一种具体实现
  • 通过引入一个新的外观角色来降低原有系统的复杂度,同时降低客户类与子系统的耦合度
  • 所指的子系统是一个广义的概念,它可以是一个类、一个功能模块、系统的一个组成部分或者一个完整的系统

六、总结

模式优点

  • 它对客户端屏蔽了子系统组件,减少了客户端所需处理的对象数目,并使得子系统使用起来更加容易
  • 它实现了子系统与客户端之间的松耦合关系,这使得子系统的变化不会影响到调用它的客户端,只需要调整外观类即可
  • 一个子系统的修改对其他子系统没有任何影响,而且子系统的内部变化也不会影响到外观对象

模式缺点

  • 不能很好地限制客户端直接使用子系统类,如果对客户端访问子系统类做太多的限制则减少了可变性和灵活性
  • 如果设计不当,增加新的子系统可能需要修改外观类的源代码,违背了开闭原则

使用情形

  • 要为访问一系列复杂的子系统提供一个简单入口
  • 客户端程序与多个子系统之间存在很大的依赖性
  • 层次化结构中,可以使用外观模式定义系统中每一层的入口,层与层之间不直接产生联系,而是通过外观类建立联系,降低层之间的耦合度