外观模式
基础概念
什么是外观模式?
答案: 外观模式(Facade Pattern)为子系统中的一组接口提供一个统一的高层接口,使得子系统更容易使用。
使用场景:
- 为复杂子系统提供简单接口
- 客户端与多个子系统有依赖
- 构建分层系统
优点:
- 简化接口
- 解耦客户端和子系统
- 更好的分层
缺点:
- 不符合开闭原则
- 增加外观类
实现方式
基本实现?
答案:
java
// 子系统A
public class SubSystemA {
public void operationA() {
System.out.println("子系统A的操作");
}
}
// 子系统B
public class SubSystemB {
public void operationB() {
System.out.println("子系统B的操作");
}
}
// 子系统C
public class SubSystemC {
public void operationC() {
System.out.println("子系统C的操作");
}
}
// 外观类
public class Facade {
private SubSystemA systemA;
private SubSystemB systemB;
private SubSystemC systemC;
public Facade() {
this.systemA = new SubSystemA();
this.systemB = new SubSystemB();
this.systemC = new SubSystemC();
}
public void operation() {
systemA.operationA();
systemB.operationB();
systemC.operationC();
}
}
// 使用
Facade facade = new Facade();
facade.operation();实际应用
家庭影院系统
答案:
java
// 投影仪
public class Projector {
public void on() {
System.out.println("投影仪打开");
}
public void off() {
System.out.println("投影仪关闭");
}
}
// 音响
public class Stereo {
public void on() {
System.out.println("音响打开");
}
public void setVolume(int volume) {
System.out.println("音量设置为: " + volume);
}
public void off() {
System.out.println("音响关闭");
}
}
// DVD播放器
public class DVDPlayer {
public void on() {
System.out.println("DVD播放器打开");
}
public void play(String movie) {
System.out.println("播放电影: " + movie);
}
public void off() {
System.out.println("DVD播放器关闭");
}
}
// 灯光
public class Light {
public void dim(int level) {
System.out.println("灯光调暗至: " + level + "%");
}
public void on() {
System.out.println("灯光打开");
}
}
// 家庭影院外观
public class HomeTheaterFacade {
private Projector projector;
private Stereo stereo;
private DVDPlayer dvdPlayer;
private Light light;
public HomeTheaterFacade() {
this.projector = new Projector();
this.stereo = new Stereo();
this.dvdPlayer = new DVDPlayer();
this.light = new Light();
}
public void watchMovie(String movie) {
System.out.println("准备观看电影...");
light.dim(10);
projector.on();
stereo.on();
stereo.setVolume(20);
dvdPlayer.on();
dvdPlayer.play(movie);
}
public void endMovie() {
System.out.println("关闭影院...");
dvdPlayer.off();
stereo.off();
projector.off();
light.on();
}
}
// 使用
HomeTheaterFacade homeTheater = new HomeTheaterFacade();
homeTheater.watchMovie("阿凡达");
homeTheater.endMovie();电商下单系统
答案:
java
// 库存系统
public class InventoryService {
public boolean checkStock(Long productId, int quantity) {
System.out.println("检查库存");
return true;
}
public void lockStock(Long productId, int quantity) {
System.out.println("锁定库存");
}
}
// 支付系统
public class PaymentService {
public boolean pay(Long orderId, BigDecimal amount) {
System.out.println("处理支付");
return true;
}
}
// 物流系统
public class LogisticsService {
public void createShipment(Long orderId) {
System.out.println("创建物流单");
}
}
// 通知系统
public class NotificationService {
public void sendOrderNotification(Long orderId) {
System.out.println("发送订单通知");
}
}
// 订单外观
public class OrderFacade {
private InventoryService inventoryService;
private PaymentService paymentService;
private LogisticsService logisticsService;
private NotificationService notificationService;
public OrderFacade() {
this.inventoryService = new InventoryService();
this.paymentService = new PaymentService();
this.logisticsService = new LogisticsService();
this.notificationService = new NotificationService();
}
public boolean createOrder(Long productId, int quantity, BigDecimal amount) {
// 1. 检查库存
if (!inventoryService.checkStock(productId, quantity)) {
return false;
}
// 2. 锁定库存
inventoryService.lockStock(productId, quantity);
// 3. 处理支付
Long orderId = 123L;
if (!paymentService.pay(orderId, amount)) {
return false;
}
// 4. 创建物流
logisticsService.createShipment(orderId);
// 5. 发送通知
notificationService.sendOrderNotification(orderId);
return true;
}
}
// 使用
OrderFacade orderFacade = new OrderFacade();
boolean success = orderFacade.createOrder(1L, 2, new BigDecimal("100.00"));Spring中的外观模式
JdbcTemplate?
答案:
java
// JdbcTemplate是外观模式的应用
@Autowired
private JdbcTemplate jdbcTemplate;
// 简化了JDBC的复杂操作
public User getUser(Long id) {
return jdbcTemplate.queryForObject(
"SELECT * FROM user WHERE id = ?",
new BeanPropertyRowMapper<>(User.class),
id
);
}
// 内部封装了:
// 1. 获取连接
// 2. 创建Statement
// 3. 执行SQL
// 4. 处理结果集
// 5. 关闭资源
// 6. 异常处理练习题
- 外观模式和适配器模式的区别?
- 外观模式和代理模式的区别?
- 什么时候使用外观模式?
- 外观模式如何体现迪米特法则?
- 如何避免外观类过于庞大?