外观模式(Java实现)
外观模式属于经典的 GoF 设计模式,提供一套覆盖底层子系统的统一接口。换句话说,外观模式定义一套高级接口,让我们能够更为方便地使用底层子系统。
子系统在演化过程中通常会越变越复杂。大多数设计模式都会导致程序里面出现一些较小的类,这一方面使得子系统更容易复用,也更容易定制,但另一方面,则会让用户处理起来较为繁杂。
外观模式能够为子系统提供一套简化的默认视图,让大多数用户都能够方便地通过该视图来使用这个子系统。只有那些需要详细定制其内容的人,才会越过外观模式直接操纵子系统中的组件。
集合框架里的 List、Set、Queue、Map 与 Enumeration 等类型可以视为某种具体集合类型的外观。例如 List,它通常由 ArrayList 或 LinkedList 等类来实现。
我们假设有个人拿到了驾照,这个驾照令其既能驾驶使用汽油的车,也能驾驶使用柴油的车,当然还能给这两种车加油。为了简化车辆的操控,我们把各种类型的车都归到 Vehicle 类型的名下。

图 1 用UML类图演示如何通过外观模式统领各种Vehicle
外观模式帮助我们管理子系统内部的依赖关系,同时又让子系统中的各个组件易于定制且易于维护。
外观模式还可以减少耦合度,并促使程序中的各部分相互分离,这是因为这个模式迫使我们把不需要出现的依赖关系,从程序中拿掉。由于外观模式能够把它下面的子系统掩盖起来,因此这个模式很自然地有利于我们对代码做横向扩展(也就是水平扩展)。
虽然外观模式好处很多,但如果误用,就会导致子系统的源代码难以维护,并令其陷入混乱。面对这种情况,我们应该重新评估当前的实现方案,并根据 SOLID 原则做出改进。
子系统在演化过程中通常会越变越复杂。大多数设计模式都会导致程序里面出现一些较小的类,这一方面使得子系统更容易复用,也更容易定制,但另一方面,则会让用户处理起来较为繁杂。
外观模式能够为子系统提供一套简化的默认视图,让大多数用户都能够方便地通过该视图来使用这个子系统。只有那些需要详细定制其内容的人,才会越过外观模式直接操纵子系统中的组件。
外观模式在JDK中的运用
前面多次提到 Java 集合框架,该框架位于 java.base 模块的 java.util 包里。JDK 中有许多地方用到了这个框架,尤其是在实现内部逻辑的时候。集合框架里的 List、Set、Queue、Map 与 Enumeration 等类型可以视为某种具体集合类型的外观。例如 List,它通常由 ArrayList 或 LinkedList 等类来实现。
外观模式范例
外观模式是软件工程中频繁使用的一种模式,而且表达起来比较容易。我们假设有个人拿到了驾照,这个驾照令其既能驾驶使用汽油的车,也能驾驶使用柴油的车,当然还能给这两种车加油。为了简化车辆的操控,我们把各种类型的车都归到 Vehicle 类型的名下。
public static void main(String[] args) { System.out.println("Pattern Facade, vehicle types"); List<Vehicle> vehicles = Arrays.asList(new DieselVehicle(), new PetrolVehicle()); for (var vehicle : vehicles) { vehicle.start(); vehicle.refuel(); } }程序输出结果如下:
Pattern Facade, vehicle types DieselVehicle, engine warm up DieselVehicle, engine start DieselVehicle, refuel diesel PetrolVehicle, engine start PetrolVehicle, refuel petrol将各种车辆都归到 Vehicle 类型的名下,对代码的结构很有好处,因为这样能够让我们实现出更加清晰的代码。

图 1 用UML类图演示如何通过外观模式统领各种Vehicle
总结
外观模式是一种使用相当频繁的模式,在开发应用程序的任何阶段都可以加以考虑。该模式不仅有助于促进接口隔离原则,而且也符合 SOLID 理念。外观模式帮助我们管理子系统内部的依赖关系,同时又让子系统中的各个组件易于定制且易于维护。
外观模式还可以减少耦合度,并促使程序中的各部分相互分离,这是因为这个模式迫使我们把不需要出现的依赖关系,从程序中拿掉。由于外观模式能够把它下面的子系统掩盖起来,因此这个模式很自然地有利于我们对代码做横向扩展(也就是水平扩展)。
虽然外观模式好处很多,但如果误用,就会导致子系统的源代码难以维护,并令其陷入混乱。面对这种情况,我们应该重新评估当前的实现方案,并根据 SOLID 原则做出改进。