外观模式 (Facade Pattern)
NOTE
外观模式为子系统中的一组接口提供一个一致的界面,定义一个高层接口,这个接口使得这一子系统更加容易使用。
📖 模式定义
外观模式是一种结构型设计模式,它为复杂的子系统提供一个简单的接口。外观模式隐藏了子系统的复杂性,并为客户端提供了一个简单的接口来访问子系统。
核心要素
- 外观类:提供简单的接口,隐藏子系统的复杂性
- 子系统类:实现子系统的功能,处理外观对象指派的工作
- 客户端:通过外观接口与子系统通信
🎯 使用场景
适用情况
- 简化复杂接口:需要为复杂的子系统提供简单接口
- 解耦客户端:客户端与多个子系统之间存在很大依赖性
- 分层系统:构建分层结构的系统
- 遗留系统集成:需要集成复杂的遗留系统
💡 实现方式
TypeScript 实现
typescript
// 子系统 - CPU
class CPU {
freeze(): void {
console.log('CPU: Freezing processor');
}
jump(position: number): void {
console.log(`CPU: Jumping to position ${position}`);
}
execute(): void {
console.log('CPU: Executing instructions');
}
}
// 子系统 - 内存
class Memory {
load(position: number, data: string): void {
console.log(`Memory: Loading data "${data}" at position ${position}`);
}
}
// 子系统 - 硬盘
class HardDrive {
read(lba: number, size: number): string {
console.log(`HardDrive: Reading ${size} bytes from LBA ${lba}`);
return 'boot data';
}
}
// 外观类 - 计算机
class ComputerFacade {
private cpu: CPU;
private memory: Memory;
private hardDrive: HardDrive;
constructor() {
this.cpu = new CPU();
this.memory = new Memory();
this.hardDrive = new HardDrive();
}
start(): void {
console.log('=== Starting Computer ===');
this.cpu.freeze();
const bootData = this.hardDrive.read(0, 1024);
this.memory.load(0, bootData);
this.cpu.jump(0);
this.cpu.execute();
console.log('=== Computer Started ===');
}
}
// 使用示例
const computer = new ComputerFacade();
computer.start();
多媒体系统外观
typescript
// 子系统 - 音频系统
class AudioSystem {
turnOn(): void {
console.log('Audio System: Turning on');
}
setVolume(volume: number): void {
console.log(`Audio System: Setting volume to ${volume}`);
}
playSound(file: string): void {
console.log(`Audio System: Playing ${file}`);
}
turnOff(): void {
console.log('Audio System: Turning off');
}
}
// 子系统 - 视频系统
class VideoSystem {
turnOn(): void {
console.log('Video System: Turning on');
}
setResolution(width: number, height: number): void {
console.log(`Video System: Setting resolution to ${width}x${height}`);
}
playVideo(file: string): void {
console.log(`Video System: Playing ${file}`);
}
turnOff(): void {
console.log('Video System: Turning off');
}
}
// 子系统 - 投影仪
class Projector {
turnOn(): void {
console.log('Projector: Turning on');
}
setInput(input: string): void {
console.log(`Projector: Setting input to ${input}`);
}
turnOff(): void {
console.log('Projector: Turning off');
}
}
// 子系统 - 灯光系统
class LightingSystem {
dim(level: number): void {
console.log(`Lighting: Dimming to ${level}%`);
}
turnOff(): void {
console.log('Lighting: Turning off');
}
turnOn(): void {
console.log('Lighting: Turning on');
}
}
// 外观类 - 家庭影院
class HomeTheaterFacade {
private audio: AudioSystem;
private video: VideoSystem;
private projector: Projector;
private lighting: LightingSystem;
constructor() {
this.audio = new AudioSystem();
this.video = new VideoSystem();
this.projector = new Projector();
this.lighting = new LightingSystem();
}
watchMovie(movie: string): void {
console.log('\n=== Starting Movie Experience ===');
this.lighting.dim(10);
this.projector.turnOn();
this.projector.setInput('HDMI');
this.audio.turnOn();
this.audio.setVolume(70);
this.video.turnOn();
this.video.setResolution(1920, 1080);
this.video.playVideo(movie);
this.audio.playSound(`${movie}_audio`);
console.log('=== Enjoy Your Movie! ===');
}
endMovie(): void {
console.log('\n=== Ending Movie Experience ===');
this.video.turnOff();
this.audio.turnOff();
this.projector.turnOff();
this.lighting.turnOn();
console.log('=== Movie Experience Ended ===');
}
listenToMusic(song: string): void {
console.log('\n=== Starting Music Experience ===');
this.lighting.dim(30);
this.audio.turnOn();
this.audio.setVolume(50);
this.audio.playSound(song);
console.log('=== Enjoy Your Music! ===');
}
}
// 使用示例
const homeTheater = new HomeTheaterFacade();
homeTheater.watchMovie('Inception');
homeTheater.endMovie();
homeTheater.listenToMusic('Classical_Symphony');
电商系统外观
typescript
// 子系统 - 库存管理
class InventoryService {
checkStock(productId: string, quantity: number): boolean {
console.log(`Inventory: Checking stock for ${productId}, quantity: ${quantity}`);
return true; // 假设有库存
}
reserveItems(productId: string, quantity: number): void {
console.log(`Inventory: Reserving ${quantity} items of ${productId}`);
}
releaseReservation(productId: string, quantity: number): void {
console.log(`Inventory: Releasing reservation for ${quantity} items of ${productId}`);
}
}
// 子系统 - 支付处理
class PaymentService {
processPayment(amount: number, paymentMethod: string): boolean {
console.log(`Payment: Processing $${amount} via ${paymentMethod}`);
return true; // 假设支付成功
}
refund(transactionId: string, amount: number): void {
console.log(`Payment: Refunding $${amount} for transaction ${transactionId}`);
}
}
// 子系统 - 物流服务
class ShippingService {
calculateShipping(address: string, weight: number): number {
console.log(`Shipping: Calculating shipping to ${address}, weight: ${weight}kg`);
return 10; // 假设运费$10
}
createShipment(orderId: string, address: string): string {
console.log(`Shipping: Creating shipment for order ${orderId} to ${address}`);
return 'SHIP123456';
}
}
// 子系统 - 通知服务
class NotificationService {
sendOrderConfirmation(email: string, orderId: string): void {
console.log(`Notification: Sending order confirmation to ${email} for order ${orderId}`);
}
sendShippingNotification(email: string, trackingNumber: string): void {
console.log(`Notification: Sending shipping notification to ${email}, tracking: ${trackingNumber}`);
}
}
// 订单数据接口
interface OrderData {
productId: string;
quantity: number;
customerEmail: string;
shippingAddress: string;
paymentMethod: string;
}
// 外观类 - 订单处理
class OrderFacade {
private inventory: InventoryService;
private payment: PaymentService;
private shipping: ShippingService;
private notification: NotificationService;
constructor() {
this.inventory = new InventoryService();
this.payment = new PaymentService();
this.shipping = new ShippingService();
this.notification = new NotificationService();
}
placeOrder(orderData: OrderData): string | null {
console.log('\n=== Processing Order ===');
try {
// 1. 检查库存
if (!this.inventory.checkStock(orderData.productId, orderData.quantity)) {
console.log('❌ Order failed: Insufficient stock');
return null;
}
// 2. 预留库存
this.inventory.reserveItems(orderData.productId, orderData.quantity);
// 3. 计算总价(简化)
const productPrice = 100; // 假设产品价格
const shippingCost = this.shipping.calculateShipping(orderData.shippingAddress, 1);
const totalAmount = productPrice * orderData.quantity + shippingCost;
// 4. 处理支付
if (!this.payment.processPayment(totalAmount, orderData.paymentMethod)) {
console.log('❌ Order failed: Payment failed');
this.inventory.releaseReservation(orderData.productId, orderData.quantity);
return null;
}
// 5. 创建订单ID
const orderId = `ORDER_${Date.now()}`;
// 6. 创建物流订单
const trackingNumber = this.shipping.createShipment(orderId, orderData.shippingAddress);
// 7. 发送确认通知
this.notification.sendOrderConfirmation(orderData.customerEmail, orderId);
this.notification.sendShippingNotification(orderData.customerEmail, trackingNumber);
console.log(`✅ Order ${orderId} placed successfully!`);
return orderId;
} catch (error) {
console.log('❌ Order failed:', error);
// 回滚操作
this.inventory.releaseReservation(orderData.productId, orderData.quantity);
return null;
}
}
cancelOrder(orderId: string): boolean {
console.log(`\n=== Canceling Order ${orderId} ===`);
try {
// 简化的取消流程
this.payment.refund('TXN123', 110); // 假设退款金额
this.inventory.releaseReservation('PROD123', 1);
this.notification.sendOrderConfirmation('customer@email.com', `${orderId}_CANCELLED`);
console.log(`✅ Order ${orderId} cancelled successfully!`);
return true;
} catch (error) {
console.log('❌ Cancel failed:', error);
return false;
}
}
}
// 使用示例
const orderSystem = new OrderFacade();
const orderData: OrderData = {
productId: 'LAPTOP001',
quantity: 1,
customerEmail: 'customer@example.com',
shippingAddress: '123 Main St, City, State',
paymentMethod: 'Credit Card'
};
const orderId = orderSystem.placeOrder(orderData);
if (orderId) {
// 模拟取消订单
setTimeout(() => {
orderSystem.cancelOrder(orderId);
}, 1000);
}
⚖️ 优缺点分析
✅ 优点
- 简化接口:为复杂子系统提供简单接口
- 解耦合:减少客户端与子系统的耦合
- 易于使用:客户端更容易使用子系统
- 灵活性:可以选择性地暴露子系统功能
❌ 缺点
- 功能限制:可能无法满足所有客户端需求
- 额外层次:增加了系统的层次结构
- 维护成本:需要维护外观类与子系统的一致性
🌟 实际应用案例
API网关外观
typescript
// 子系统服务
class UserService {
getUser(id: string): any {
console.log(`UserService: Getting user ${id}`);
return { id, name: 'John Doe', email: 'john@example.com' };
}
updateUser(id: string, data: any): void {
console.log(`UserService: Updating user ${id}`, data);
}
}
class OrderService {
getUserOrders(userId: string): any[] {
console.log(`OrderService: Getting orders for user ${userId}`);
return [{ id: 'ORDER1', amount: 100 }, { id: 'ORDER2', amount: 200 }];
}
}
class RecommendationService {
getRecommendations(userId: string): any[] {
console.log(`RecommendationService: Getting recommendations for user ${userId}`);
return [{ id: 'PROD1', name: 'Laptop' }, { id: 'PROD2', name: 'Mouse' }];
}
}
// API网关外观
class APIGateway {
private userService: UserService;
private orderService: OrderService;
private recommendationService: RecommendationService;
constructor() {
this.userService = new UserService();
this.orderService = new OrderService();
this.recommendationService = new RecommendationService();
}
getUserDashboard(userId: string): any {
console.log(`\n=== Loading User Dashboard for ${userId} ===`);
const user = this.userService.getUser(userId);
const orders = this.orderService.getUserOrders(userId);
const recommendations = this.recommendationService.getRecommendations(userId);
return {
user,
recentOrders: orders.slice(0, 3),
recommendations: recommendations.slice(0, 5),
summary: {
totalOrders: orders.length,
totalSpent: orders.reduce((sum, order) => sum + order.amount, 0)
}
};
}
}
// 使用示例
const apiGateway = new APIGateway();
const dashboard = apiGateway.getUserDashboard('USER123');
console.log('Dashboard data:', dashboard);
🔄 相关模式
- 适配器模式:适配器改变接口,外观简化接口
- 中介者模式:中介者封装对象间交互,外观简化子系统访问
- 抽象工厂模式:可以与外观模式结合使用
🚀 最佳实践
- 保持简单:外观接口应该简单易用
- 不要过度封装:允许客户端直接访问子系统(如果需要)
- 单一职责:每个外观类应该有明确的职责
- 文档化:清楚地文档化外观类的功能和限制
⚠️ 注意事项
- 功能完整性:确保外观提供足够的功能
- 性能考虑:避免外观成为性能瓶颈
- 版本兼容:子系统变化时保持外观接口稳定
- 错误处理:妥善处理子系统的错误
📚 总结
外观模式通过提供统一的接口来简化复杂子系统的使用。它特别适用于需要简化复杂API或集成多个子系统的场景。
使用建议:
- 当子系统很复杂时使用
- 当需要为子系统提供简单接口时使用
- 当需要解耦客户端与子系统时使用
- 当构建分层系统时使用
相关链接: