外观模式(Facade Pattern)

一、定义

外观模式(Facade Pattern):结构型模式之一,提供了一个统一的接口,用来访问子系统中的一群接口。外观模式定义了一个高层接口,让子系统更容易使用

二、UML类图

外观模式(Facade Pattern)_第1张图片

三、角色职责

  • 外观角色(Facade):提供一个外观接口,对外,它提供一个易于客户端访问的接口,对内,它可以访问子系统中的所有功能。
  • 子系统角色(SubSystem):子系统在整个系统中可以是一个或多个模块,每个模块都有若干类组成,这些类可能相互之间有着比较复杂的关系。
  • 客户端(Client):外观接口调用测试者。

四、代码实现

前言:举个栗子,我们家里有很多家居,比如空调、热水器、窗帘、扫地机器人,假设这些家居都是由不同的对象来进行控制的,就会有空调控制对象、热水器控制对象、窗帘控制对象、扫地机器人控制对象。然而,这些我们都可以不需要,我们只需要一个小爱同学音箱,就可以把这些控制都集中再一个控制器上,我们需要开空调,只需要对小爱同学说开空调就可以了。所以之前的其他遥控器我们都可以不用关心了,我们只需要关注小爱同学就够了。这个时候我们就可以使用外观模式。

空调(子系统角色 SubSystem)

@AllArgsConstructor
@NoArgsConstructor
@Data
public class AirConditioner {
    private static AirConditioner airConditioner = new AirConditioner();

    public static AirConditioner getInstance() {
        return airConditioner;
    }

    public void turnOn() {
        System.out.println("打开空调");
    }

    public void turnOff() {
        System.out.println("关闭空调");
    }
}

热水器(子系统角色 SubSystem)

public class Calorifier {
    private static Calorifier calorifier = new Calorifier();

    public static Calorifier getInstance() {
        return calorifier;
    }

    public void turnOn() {
        System.out.println("打开热水器");
    }

    public void turnOff() {
        System.out.println("关闭热水器");
    }
}

窗帘(子系统角色 SubSystem)

public class Curtain {
    private static Curtain curtain = new Curtain();

    public static Curtain getInstance() {
        return curtain;
    }

    public void turnOn() {
        System.out.println("打开窗帘");
    }

    public void turnOff() {
        System.out.println("关闭窗帘");
    }
}

扫地机器人(子系统角色 SubSystem)

public class FloorMoppingRobot {
    private static FloorMoppingRobot floorMoppingRobot = new FloorMoppingRobot();

    public static FloorMoppingRobot getInstance() {
        return floorMoppingRobot;
    }

    public void turnOn() {
        System.out.println("打开扫地机器人");
    }

    public void turnOff() {
        System.out.println("关闭扫地机器人");
    }
}

小爱同学(外观角色 Facade)

public class XiaoaiClassmate {
    // 定义子系统对象
    private AirConditioner airConditioner;
    private Calorifier calorifier;
    private Curtain curtain;
    private FloorMoppingRobot floorMoppingRobot;

    // 通过构造器根据单例模式获得子系统对象
    public XiaoaiClassmate() {
        this.airConditioner = AirConditioner.getInstance();
        this.calorifier = Calorifier.getInstance();
        this.curtain = Curtain.getInstance();
        this.floorMoppingRobot = FloorMoppingRobot.getInstance();
    }

    public void getUp() {
        System.out.println("我要起床啦!");
        airConditioner.turnOn();
        calorifier.turnOn();
        curtain.turnOff();
    }

    public void goToWork() {
        System.out.println("我要去上班啦");
        airConditioner.turnOff();
        calorifier.turnOff();
        floorMoppingRobot.turnOn();
    }
}

测试类

public class FacadeTest {
    public static void main(String[] args) {
        XiaoaiClassmate xiaoaiClassmate = new XiaoaiClassmate();
        xiaoaiClassmate.getUp();
        xiaoaiClassmate.goToWork();
    }
}

输出结果

我要起床啦!
打开空调
打开热水器
关闭窗帘
我要去上班啦
关闭空调
关闭热水器
打开扫地机器人

五、源码分析

外观模式(Facade Pattern)_第2张图片
在Mybatis中的Configuration类里,就使用到了外观模式。我们只需要调用Configuration类的newMetaObject()方法,并传递一个Object类型参数,就可以得到MetaObject对象,客户端并不需要关心这个对象是如何生成的。我们点进Configuration类。
在这里插入图片描述
那MetaObject是如何产生的呢?我们点进forObject()方法。
外观模式(Facade Pattern)_第3张图片
可以看到,forObject会调用MetaObject的构造方法,然后根据你传入的对象类型去构建一个MetaObject对象并返回。这就是典型的外观模式。

六、优缺点分析

优点

  • 使复杂子系统的接口变的简单可用,实现了子系统与客户之间的松耦合关系,减少了客户端对子系统的依赖,这使得子系统的组件变化不会影响到调用它的客户类,只需要调整外观类即可。外观模式也遵循了迪米特法则。

缺点

  • 在不对外观类进行抽象的时候,如果需要添加新的子系统,就需要对外观类进行修改,违背了开闭原则。

七、适用场景

对分层结构系统构建时,使用外观模式定义子系统中每层的入口点可以简化子系统之间的依赖关系。当一个复杂系统的子系统很多时,外观模式可以为系统设计一个简单的接口供外界访问

八、总结

外观模式对客户端与子系统的耦合关系,让子系统内部的模块更易维护和扩展。对外屏蔽了子系统的细节,因此外观模式降低了客户端对子系统使用的复杂性。当系统需要进行分层设计时,可以考虑外观模式帮我们更好的划分访问的层次。

你可能感兴趣的:(设计模式,外观模式)