外观模式(Facade Pattern)是一种结构型设计模式,它提供了一个简化复杂系统的接口,用于与系统交互。外观模式通过创建一个高级别的接口,将一组相关的子系统接口封装在一起,以提供更简单、更统一的接口给客户端使用。
外观模式的核心思想是将复杂系统的内部结构隐藏起来,只暴露出一个简化的接口,使客户端可以更容易地与系统交互,而不必了解系统的复杂性。这有助于降低客户端与系统之间的耦合度,并提供了一种更高级别、更易用的界面。
外观模式是迪米特法则的典型应用。
以下是外观模式的一些重要组成部分:
外观(Facade): 外观是外观模式的核心,它是一个包含高级别接口的类或接口。外观通常封装了一个或多个子系统的复杂操作,并为客户端提供了一个简单的入口点。
子系统(Subsystem): 子系统是复杂系统的各个部分,它们包含了系统的实际实现。外观模式的目标是隐藏子系统的复杂性,因此客户端不需要与子系统的具体类直接交互。
客户端(Client): 客户端是使用外观模式的部分,它通过外观接口与系统交互,而不需要了解系统内部的复杂细节。
以下是一个实现外观模式的示例。在这个示例中,将创建一个音响系统的外观,以封装与音响系统相关的复杂操作。
首先定义子系统的一些类,包括音响、投影仪和DVD播放器:
// 子系统类1:音响
class StereoSystem {
public void turnOn() {
System.out.println("音响已打开");
}
public void turnOff() {
System.out.println("音响已关闭");
}
public void setVolume(int volume) {
System.out.println("音响音量已设置为 " + volume);
}
}
// 子系统类2:投影仪
class Projector {
public void turnOn() {
System.out.println("投影仪已打开");
}
public void turnOff() {
System.out.println("投影仪已关闭");
}
public void setInput(String input) {
System.out.println("投影仪输入源已设置为 " + input);
}
}
// 子系统类3:DVD播放器
class DVDPlayer {
public void turnOn() {
System.out.println("DVD播放器已打开");
}
public void turnOff() {
System.out.println("DVD播放器已关闭");
}
public void play(String movie) {
System.out.println("正在播放电影: " + movie);
}
}
接下来,创建外观类 HomeTheaterFacade,它封装了上述子系统的操作,并提供了一个简化的接口供客户端使用:
// 外观类
class HomeTheater {
private StereoSystem stereoSystem;
private Projector projector;
private DVDPlayer dvdPlayer;
public HomeTheater() {
stereoSystem = new StereoSystem();
projector = new Projector();
dvdPlayer = new DVDPlayer();
}
public void watchMovie(String movie, int volume) {
System.out.println("准备播放电影...");
projector.turnOn();
projector.setInput("DVD");
stereoSystem.turnOn();
stereoSystem.setVolume(volume);
dvdPlayer.turnOn();
dvdPlayer.play(movie);
}
public void endMovie() {
System.out.println("电影结束,正在关闭设备...");
projector.turnOff();
stereoSystem.turnOff();
dvdPlayer.turnOff();
}
}
最后,我们可以在客户端中使用外观模式,而不必直接与子系统的复杂操作交互:
public class Client {
public static void main(String[] args) {
HomeTheater homeTheater = new HomeTheater();
// 观看电影
homeTheater.watchMovie("Avatar", 20);
// 电影结束
homeTheater.endMovie();
}
}
在这个示例中,HomeTheaterFacade 封装了音响、投影仪和DVD播放器的复杂操作,客户端只需要通过外观类的接口来操作整个家庭影院系统。这使得客户端的代码更简单、更易读,同时隐藏了系统的复杂性。
外观模式的优点包括:
外观模式常见的应用场景包括:
在JDBC中,java.sql.DriverManager 类可以看作是一个外观类,封装了底层数据库驱动程序的加载和数据库连接管理,使开发者能够更轻松地与各种数据库交互。
以下是一个简单的示例,演示了如何使用java.sql.DriverManager 来建立数据库连接和执行SQL查询:
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class JDBCFacadeExample {
public static void main(String[] args) {
// JDBC数据库连接信息
String url = "jdbc:mysql://localhost:3306/test";
String user = "root";
String password = "123456";
try {
// 加载数据库驱动程序(这部分由DriverManager处理)
Class.forName("com.mysql.cj.jdbc.Driver");
// 建立数据库连接(也由DriverManager处理)
Connection connection = DriverManager.getConnection(url, user, password);
// 创建SQL语句
String sql = "SELECT * FROM employees";
// 创建并执行SQL查询
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery(sql);
// 处理查询结果
while (resultSet.next()) {
int id = resultSet.getInt("id");
String name = resultSet.getString("name");
double salary = resultSet.getDouble("salary");
System.out.println("Employee ID: " + id);
System.out.println("Name: " + name);
System.out.println("Salary: " + salary);
}
// 关闭资源(连接、语句和结果集)
resultSet.close();
statement.close();
connection.close();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
在上述示例中,JDBC的子系统包括以下组成部分:
java.sql.Connection 接口来表示数据库连接。连接管理包括连接的创建、关闭、连接池管理等任务。这是JDBC底层的复杂性之一。java.sql.Statement 对象或java.sql.PreparedStatement 对象,以及执行查询、更新或批处理操作。SQL查询的执行是与数据库交互的核心任务。java.sql.ResultSet 对象,其中包含查询结果集。开发者需要遍历结果集并提取数据以供应用程序使用。结果集处理是另一个重要的子系统。而java.sql.DriverManager 类充当了外观,封装了底层的数据库驱动程序加载和数据库连接管理。开发者只需提供数据库连接信息,然后通过它来获取连接并执行SQL查询,而无需了解驱动程序加载、连接池等底层细节。
通过这种方式,JDBC使得与各种数据库交互变得更加简单和统一,开发者只需关注业务逻辑和SQL查询,而无需处理复杂的数据库连接管理。这正是外观模式的一个典型应用,简化了复杂系统的接口,提供了一个更高级别、更易用的界面。