外观模式
约 521 字
外观模式
核心思想
外观模式提供了一个统一的接口来访问子系统中的一组接口。
典型用例
整合微服务接口
在微服务架构中,外观模式可以用来提供一个统一的接口来整合多个微服务,使得客户端不需要与每个服务单独交互。
在这个例子中,外观服务类提供了一个统一的接口来访问多个微服务接口。客户端代码通过与外观类来交互,而不是直接与每个微服务交互。
// npm run code src/code/design-pattern/facade/unify-microservices.ts
export {};
// 假设有几个微服务,每个服务都有自己的接口
// 用户服务
class UserService {
getUser(userId: string): string {
return `User info for ${userId}`;
}
}
// 订单服务
class OrderService {
getOrder(orderId: string): string {
return `Order details for ${orderId}`;
}
}
// 支付服务
class PaymentService {
processPayment(amount: number): string {
return `Processed payment of $${amount}`;
}
}
// 创建一个外观类来封装对微服务的访问
class ServicesFacade {
private userService: UserService;
private orderService: OrderService;
private paymentService: PaymentService;
constructor() {
this.userService = new UserService();
this.orderService = new OrderService();
this.paymentService = new PaymentService();
}
getUserInfo(userId: string): string {
return this.userService.getUser(userId);
}
getOrderDetails(orderId: string): string {
return this.orderService.getOrder(orderId);
}
makePayment(amount: number): string {
return this.paymentService.processPayment(amount);
}
}
const servicesFacade = new ServicesFacade();
// 客户端现在可以通过外观接口来访问服务,而无需直接与每个服务交互
console.log(servicesFacade.getUserInfo("user123"));
console.log(servicesFacade.getOrderDetails("order456"));
console.log(servicesFacade.makePayment(100));
简化复杂子系统的访问
当子系统变得复杂或者当需要简化子系统的一组接口时,外观模式可以用于提供一个简单的接口给外部客户端。这在涉及到复杂库、框架或API集合的情况下尤其有用。
// npm run code src/code/design-pattern/facade/simplify-access-to-complex-subsystems.ts
export {};
// 定义复杂子系统的类
class SystemA {
operationA(): string {
return 'SystemA operation';
}
}
class SystemB {
operationB(): string {
return 'SystemB operation';
}
}
class SystemC {
operationC(): string {
return 'SystemC operation';
}
}
// 创建外观类
class Facade {
private systemA: SystemA;
private systemB: SystemB;
private systemC: SystemC;
constructor() {
this.systemA = new SystemA();
this.systemB = new SystemB();
this.systemC = new SystemC();
}
// 提供给外部的简化接口
operate(): string {
const resultA = this.systemA.operationA();
const resultB = this.systemB.operationB();
const resultC = this.systemC.operationC();
// 组合子系统的操作
return `${resultA} | ${resultB} | ${resultC}`;
}
}
// 客户端代码
const facade = new Facade();
console.log(facade.operate());
封装客户端和子系统的交互
在需要将客户端与子系统的直接交互隔离开时,外观可以作为一个中间层来保护子系统不受客户端的影响,同时也简化客户端对子系统的使用。
// npm run code src/code/design-pattern/facade/encapsulate-client-and-subsystem-interactions.ts
export {};
// 子系统类
class SubsystemOne {
operationOne(): string {
return 'SubsystemOne: Ready!';
}
operationN(): string {
return 'SubsystemOne: Go!';
}
}
class SubsystemTwo {
operationOne(): string {
return 'SubsystemTwo: Get ready!';
}
operationZ(): string {
return 'SubsystemTwo: Fire!';
}
}
// 外观类
class Facade {
private subsystemOne: SubsystemOne;
private subsystemTwo: SubsystemTwo;
constructor(subsystemOne: SubsystemOne, subsystemTwo: SubsystemTwo) {
this.subsystemOne = subsystemOne || new SubsystemOne();
this.subsystemTwo = subsystemTwo || new SubsystemTwo();
}
// 外观类提供的简化接口
operation(): string {
let result = 'Facade initializes subsystems:\n';
result += this.subsystemOne.operationOne();
result += this.subsystemTwo.operationOne();
result += 'Facade orders subsystems to perform the action:\n';
result += this.subsystemOne.operationN();
result += this.subsystemTwo.operationZ();
return result;
}
}
// 客户端代码
const subsystemOne = new SubsystemOne();
const subsystemTwo = new SubsystemTwo();
const facade = new Facade(subsystemOne, subsystemTwo);
// 客户端通过外观类与子系统交互
console.log(facade.operation());
提供子系统的抽象层
当子系统的实现和客户端代码可能经常变化时,外观模式可以用来为子系统提供一个稳定的接口,隔离了子系统的实现细节和客户端的直接交互,从而减少系统的耦合度。
// npm run code src/code/design-pattern/facade/provides-abstraction-layer-for-subsystem.ts
export {};
// 子系统类
class SubsystemOne {
complexOperationOne(): string {
return 'SubsystemOne: Complex operation';
}
}
class SubsystemTwo {
complexOperationTwo(): string {
return 'SubsystemTwo: Complex operation';
}
}
// 外观类
class Facade {
private subsystemOne: SubsystemOne;
private subsystemTwo: SubsystemTwo;
constructor(subsystemOne: SubsystemOne, subsystemTwo: SubsystemTwo) {
this.subsystemOne = subsystemOne || new SubsystemOne();
this.subsystemTwo = subsystemTwo || new SubsystemTwo();
}
// 外观类提供的稳定接口
operation(): string {
const resultOne = this.subsystemOne.complexOperationOne();
const resultTwo = this.subsystemTwo.complexOperationTwo();
return `Facade coordinates operations: \n${resultOne}\n${resultTwo}`;
}
}
// 客户端代码
const facade = new Facade(new SubsystemOne(), new SubsystemTwo());
console.log(facade.operation());
分层结构中的接口
在多层架构的应用程序中,外观模式可以用于定义系统中每一层的入口点,使得层与层之间的通信更加清晰和有序。
// npm run code src/code/design-pattern/facade/interfaces-in-hierarchical-structure.ts
export {};
// 数据访问层(DAL)
class DataAccessLayer {
fetchData(): string {
return 'Data fetched from database';
}
}
// 业务逻辑层(BLL)
class BusinessLogicLayer {
private dal: DataAccessLayer;
constructor(dal: DataAccessLayer) {
this.dal = dal;
}
processData(): string {
const data = this.dal.fetchData();
return `Processed ${data}`;
}
}
// 表示层(UI)
class PresentationLayer {
private bll: BusinessLogicFacade; // 使用 BusinessLogicFacade
constructor(bll: BusinessLogicFacade) {
this.bll = bll;
}
displayData(): void {
const processedData = this.bll.processData();
console.log(`Displaying ${processedData}`);
}
}
// 外观类为每一层
class DataAccessFacade {
private dal: DataAccessLayer;
constructor() {
this.dal = new DataAccessLayer();
}
fetchData(): string {
return this.dal.fetchData();
}
}
class BusinessLogicFacade {
private bll: BusinessLogicLayer;
constructor(dalFacade: DataAccessFacade) {
const dal = dalFacade; // 使用 DataAccessFacade
this.bll = new BusinessLogicLayer(dal);
}
processData(): string {
return this.bll.processData();
}
}
class PresentationFacade {
private pl: PresentationLayer;
constructor(bllFacade: BusinessLogicFacade) {
this.pl = new PresentationLayer(bllFacade);
}
displayData(): void {
this.pl.displayData();
}
}
// 客户端代码
const dalFacade = new DataAccessFacade();
const bllFacade = new BusinessLogicFacade(dalFacade);
const presentationFacade = new PresentationFacade(bllFacade);
presentationFacade.displayData();