外观
更新: 6/28/2025 字数: 0 字 时长: 0 分钟
定义
外观模式 (Facade Pattern) 为复杂的子系统提供一个统一的简单接口,隐藏系统内部复杂性,降低客户端与子系统的耦合度。外观模式通过定义高层接口简化系统使用,是迪米特法则的典型应用。
角色
- 外观 (Facade):提供统一的高级接口
- 子系统类 (Subsystem Classes):实现子系统功能的多个类
- 客户端 (Client):通过外观与子系统交互
实现
家庭影院系统示例
java
// 子系统类:投影仪
public class Projector {
public void on() {
System.out.println("投影仪开启");
}
public void wideScreenMode() {
System.out.println("投影仪设置为宽屏模式");
}
public void off() {
System.out.println("投影仪关闭");
}
}
// 子系统类:音响系统
public class SoundSystem {
public void on() {
System.out.println("音响系统开启");
}
public void setVolume(int level) {
System.out.println("音量设置为:" + level);
}
public void off() {
System.out.println("音响系统关闭");
}
}
// 子系统类:蓝光播放器
public class BluRayPlayer {
public void on() {
System.out.println("蓝光播放器开启");
}
public void play(String movie) {
System.out.println("开始播放电影:" + movie);
}
public void off() {
System.out.println("蓝光播放器关闭");
}
}
// 外观类
public class HomeTheaterFacade {
private Projector projector;
private SoundSystem soundSystem;
private BluRayPlayer bluRayPlayer;
public HomeTheaterFacade(Projector projector,
SoundSystem soundSystem,
BluRayPlayer bluRayPlayer) {
this.projector = projector;
this.soundSystem = soundSystem;
this.bluRayPlayer = bluRayPlayer;
}
public void watchMovie(String movie) {
System.out.println("准备观看电影...");
projector.on();
projector.wideScreenMode();
soundSystem.on();
soundSystem.setVolume(8);
bluRayPlayer.on();
bluRayPlayer.play(movie);
}
public void endMovie() {
System.out.println("结束观看电影...");
bluRayPlayer.off();
soundSystem.off();
projector.off();
}
}
// 客户端使用
public class Client {
public static void main(String[] args) {
// 创建子系统组件
Projector projector = new Projector();
SoundSystem soundSystem = new SoundSystem();
BluRayPlayer bluRayPlayer = new BluRayPlayer();
// 创建外观
HomeTheaterFacade homeTheater =
new HomeTheaterFacade(projector, soundSystem, bluRayPlayer);
// 通过外观使用复杂系统
homeTheater.watchMovie("盗梦空间");
// ...观看电影...
homeTheater.endMovie();
}
}
数据库连接外观示例
java
// 外观类:简化数据库操作
public class DatabaseFacade {
private Connection connection;
public DatabaseFacade(String url, String user, String password) {
try {
connection = DriverManager.getConnection(url, user, password);
} catch (SQLException e) {
throw new RuntimeException("数据库连接失败", e);
}
}
public void executeUpdate(String sql) {
try (Statement stmt = connection.createStatement()) {
stmt.executeUpdate(sql);
} catch (SQLException e) {
handleException(e);
}
}
public List<Map<String, Object>> executeQuery(String sql) {
List<Map<String, Object>> results = new ArrayList<>();
try (Statement stmt = connection.createStatement();
ResultSet rs = stmt.executeQuery(sql)) {
ResultSetMetaData metaData = rs.getMetaData();
int columnCount = metaData.getColumnCount();
while (rs.next()) {
Map<String, Object> row = new HashMap<>();
for (int i = 1; i <= columnCount; i++) {
String columnName = metaData.getColumnName(i);
row.put(columnName, rs.getObject(i));
}
results.add(row);
}
} catch (SQLException e) {
handleException(e);
}
return results;
}
public void close() {
try {
if (connection != null && !connection.isClosed()) {
connection.close();
}
} catch (SQLException e) {
// 静默关闭
}
}
private void handleException(SQLException e) {
// 统一的异常处理逻辑
throw new RuntimeException("数据库操作失败:" + e.getMessage(), e);
}
}
优缺点
优点:
- 简化复杂系统使用
- 降低客户端与子系统的耦合度
- 提高子系统独立性和可移植性
- 符合迪米特法则(最少知识原则)
缺点:
- 不限制直接访问子系统(需要约定)
- 增加新功能可能需要修改外观
- 可能成为"上帝对象"(过度集中功能)
应用场景
- 复杂子系统需要简单入口
- 分层系统结构(每层提供统一接口)
- 遗留系统重构(包装旧接口)
- 第三方库简化封装
- 微服务网关(API Gateway)
与其他模式的关系
- 与适配器模式:适配器转换接口,外观简化接口
- 与中介者模式:中介者协调对象间通信,外观协调子系统间通信
- 与单例模式:外观常实现为单例
- 与抽象工厂模式:抽象工厂可创建子系统对象
- 与代理模式:代理控制访问,外观简化访问
JDK 中的外观模式
javax.faces.context.FacesContext
(JSF)java.net.URL
(封装 URLConnection 等)javax.servlet.http.HttpSession
(Servlet API)java.util.logging.Logger
(日志门面)- SLF4J 日志门面
注意事项
- 合理划分子系统边界
- 避免外观类过度膨胀
- 提供子系统直接访问通道(高级用户)
- 考虑为不同客户端提供不同外观
- 注意线程安全问题(共享子系统状态)