1、简述
外观模式(Facade Pattern)是一种结构型设计模式,通过为多个复杂子系统提供一个一致的接口,使得子系统之间的交互更加简单,降低了客户端和子系统之间的耦合。
设计模式样例:https://gitee.com/lhdxhl/design-pattern-example.git
2、什么是外观模式
外观模式的核心是提供一个高级接口,使得子系统的使用变得简单。通过引入外观类,客户端可以不直接与子系统交互,从而屏蔽了子系统的复杂性。
外观模式的优点:
- 降低复杂性:通过引入一个外观类,客户端可以更轻松地与子系统交互。
- 松散耦合:客户端和子系统之间的耦合被外观类隔离,方便系统的扩展和维护。
- 更好的分层设计:外观类可以作为系统的入口点,帮助我们更清晰地划分层次。
3、实际案例
假设我们有一个家庭影院系统,包括电视、音响和 DVD 播放器。为了看电影,用户需要分别打开这些设备,并设置好输入输出,非常麻烦。我们可以通过外观模式封装这些复杂操作。
// 子系统 1:电视
public class TV {
public void turnOn() {
System.out.println("TV is turned on.");
}
public void turnOff() {
System.out.println("TV is turned off.");
}
}
// 子系统 2:音响
public class SoundSystem {
public void turnOn() {
System.out.println("Sound system is turned on.");
}
public void setVolume(int level) {
System.out.println("Sound system volume set to " + level);
}
public void turnOff() {
System.out.println("Sound system is turned off.");
}
}
// 子系统 3:DVD 播放器
public class DVDPlayer {
public void turnOn() {
System.out.println("DVD player is turned on.");
}
public void play(String movie) {
System.out.println("Playing movie: " + movie);
}
public void turnOff() {
System.out.println("DVD player is turned off.");
}
}
// 外观类
public class HomeTheaterFacade {
private TV tv;
private SoundSystem soundSystem;
private DVDPlayer dvdPlayer;
public HomeTheaterFacade(TV tv, SoundSystem soundSystem, DVDPlayer dvdPlayer) {
this.tv = tv;
this.soundSystem = soundSystem;
this.dvdPlayer = dvdPlayer;
}
public void watchMovie(String movie) {
System.out.println("Setting up home theater...");
tv.turnOn();
soundSystem.turnOn();
soundSystem.setVolume(20);
dvdPlayer.turnOn();
dvdPlayer.play(movie);
System.out.println("Enjoy your movie!");
}
public void endMovie() {
System.out.println("Shutting down home theater...");
dvdPlayer.turnOff();
soundSystem.turnOff();
tv.turnOff();
}
}
// 测试代码
public class FacadePatternDemo {
public static void main(String[] args) {
TV tv = new TV();
SoundSystem soundSystem = new SoundSystem();
DVDPlayer dvdPlayer = new DVDPlayer();
HomeTheaterFacade homeTheater = new HomeTheaterFacade(tv, soundSystem, dvdPlayer);
homeTheater.watchMovie("Inception");
System.out.println();
homeTheater.endMovie();
}
}
输出结果
Setting up home theater...
TV is turned on.
Sound system is turned on.
Sound system volume set to 20
DVD player is turned on.
Playing movie: Inception
Enjoy your movie!
Shutting down home theater...
DVD player is turned off.
Sound system is turned off.
TV is turned off.
4、应用场景
- 简化复杂子系统的使用:例如,整合多个子系统的接口,提供统一操作入口。
- 分层架构:外观模式可以用作系统分层的入口,使得高层模块不直接依赖底层模块,遵循 "迪米特法则"。
- 旧系统的重构:通过外观模式,可以封装旧系统的复杂接口,提供更友好的访问方式。
4.1 数据库连接管理
在很多数据库应用中,可以通过外观模式封装连接池的创建、获取和关闭操作:
public class DatabaseConnectionFacade {
private ConnectionPool connectionPool;
public DatabaseConnectionFacade(ConnectionPool pool) {
this.connectionPool = pool;
}
public Connection getConnection() {
return connectionPool.getConnection();
}
public void releaseConnection(Connection connection) {
connectionPool.releaseConnection(connection);
}
}
4.2. Web 应用开发
在 Spring 框架中,DispatcherServlet
就是一个外观模式的经典例子,它封装了请求的分发、视图解析等功能,对开发者隐藏了内部复杂实现。
4.3 第三方 API 封装
使用外观模式对复杂的第三方 API 进行封装,提供一个简化的接口。例如,对支付系统(支付宝、微信支付等)的统一封装:
public class PaymentFacade {
private AlipayService alipayService;
private WechatPayService wechatPayService;
public PaymentFacade(AlipayService alipayService, WechatPayService wechatPayService) {
this.alipayService = alipayService;
this.wechatPayService = wechatPayService;
}
public void payWithAlipay(double amount) {
alipayService.pay(amount);
}
public void payWithWechat(double amount) {
wechatPayService.pay(amount);
}
}
5、总结
外观模式通过提供一个简化的接口,帮助开发者轻松使用复杂的子系统。它不仅降低了客户端的学习成本,还提高了代码的可维护性。在开发中,通过合理地使用外观模式,可以显著改善系统的设计质量。
评论区