0119_外观模式(Facade)
外观模式(Facade)
意图
为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
UML 图

优点
- 简化客户端使用:客户端不需要了解系统内部的复杂实现,只需要与外观对象交互
- 降低耦合度:将客户端与子系统解耦,使得子系统的变化不会影响到客户端
- 提高可维护性:将复杂的子系统调用封装起来,便于维护和修改
- 符合迪米特法则:客户端只与外观对象交互,减少了与其他对象的依赖
- 易于使用:提供了一个简单的接口,隐藏了系统的复杂性
缺点
- 不符合开闭原则:如果需要添加新的功能,通常需要修改外观类
- 可能成为上帝对象:如果过度使用,外观类可能变得过于庞大和复杂
- 限制了灵活性:客户端无法直接访问子系统的特定功能
- 可能产生性能问题:额外的调用层可能带来轻微的性能开销
代码示例
以上班打开电脑、工作运行电脑、下班关闭电脑为例,电脑包含多个子系统(CPU、硬盘、内存等)。使用外观模式提供一个统一的控制接口:
1. 子系统类 (Subsystem Classes)
// CPU
public class CPU {
public void start() {
System.out.println("CPU启动中...");
System.out.println("CPU初始化完成");
}
public void shutdown() {
System.out.println("CPU关闭中...");
System.out.println("CPU已关闭");
}
public void execute() {
System.out.println("CPU执行指令");
}
}
// 硬盘子系统
public class HardDrive {
public void start() {
System.out.println("硬盘启动中...");
System.out.println("硬盘初始化完成");
}
public void shutdown() {
System.out.println("硬盘关闭中...");
System.out.println("硬盘已关闭");
}
public void read() {
System.out.println("硬盘读取数据");
}
public void write() {
System.out.println("硬盘写入数据");
}
}
// 内存子系统
public class Memory {
public void start() {
System.out.println("内存启动中...");
System.out.println("内存初始化完成");
}
public void shutdown() {
System.out.println("内存关闭中...");
System.out.println("内存已关闭");
}
public void load() {
System.out.println("内存加载数据");
}
}
2. 外观类 (Facade Class)
// 电脑外观类
public class ComputerFacade {
private CPU cpu;
private Memory memory;
private HardDrive hardDrive;
public ComputerFacade() {
this.cpu = new CPU();
this.memory = new Memory();
this.hardDrive = new HardDrive();
}
/**
* 开机操作
* 按照正确的顺序启动各个子系统
*/
public void start() {
System.out.println("======= 开始启动电脑 =======");
cpu.start();
memory.start();
hardDrive.start();
System.out.println("======= 电脑启动完成 =======\n");
}
/**
* 关机操作
* 按照正确的顺序关闭各个子系统
*/
public void shutdown() {
System.out.println("======= 开始关闭电脑 =======");
hardDrive.shutdown();
memory.shutdown();
cpu.shutdown();
System.out.println("======= 电脑关闭完成 =======\n");
}
/**
* 工作操作
* 演示电脑正常工作时各组件的协作
*/
public void work() {
System.out.println("======= 电脑工作中 =======");
cpu.execute();
memory.load();
hardDrive.read();
hardDrive.write();
System.out.println("======= 工作完成 =======\n");
}
}
3. 客户端代码 (Client Code)
public class ComputerFacadeTest {
public static void main(String[] args) {
// 创建电脑外观对象
ComputerFacade computer = new ComputerFacade();
// 上班 - 开机
System.out.println("---------- 上班时间 ----------");
computer.start();
// 工作
System.out.println("---------- 开始工作 ----------");
computer.work();
// 下班 - 关机
System.out.println("---------- 下班时间 ----------");
computer.shutdown();
}
}
在Java标准库中的应用
外观模式在Java标准库和框架中有广泛应用:
-
JDBC数据库连接
// DriverManager作为外观,隐藏了数据库连接的复杂细节 Connection connection = DriverManager.getConnection(url, username, password); Statement statement = connection.createStatement(); ResultSet resultSet = statement.executeQuery("SELECT * FROM users"); -
Spring框架
// Spring的JdbcTemplate作为外观,简化了JDBC操作 jdbcTemplate.query("SELECT * FROM users", new RowMapper<User>() { @Override public User mapRow(ResultSet rs, int rowNum) throws SQLException { User user = new User(); user.setId(rs.getInt("id")); user.setName(rs.getString("name")); return user; } }); -
Servlet API
// HttpServletRequest作为外观,提供了访问HTTP请求信息的统一接口 String username = request.getParameter("username"); String password = request.getParameter("password"); String method = request.getMethod(); -
Java日志框架
// SLF4J作为外观,提供了统一的日志接口 Logger logger = LoggerFactory.getLogger(MyClass.class); logger.info("This is an info message"); logger.error("This is an error message");
总结
外观模式通过提供一个统一的接口来简化复杂系统的使用,它将客户端与子系统的复杂性隔离开来。这种模式特别适用于:
- 需要为复杂子系统提供简单入口点的场景
- 客户端不需要直接访问子系统所有功能的情况
- 想要降低系统耦合度,提高可维护性的场景
外观模式不是要封装所有子系统功能,而是提供一组常用的功能,让客户端更容易使用系统。对于需要访问特定高级功能的客户端,仍然可以直接访问子系统组件。

浙公网安备 33010602011771号