结构型模式-外观模式
外观模式
外观是一种结构型设计模式, 能为程序库、框架或其他复杂类提供一个简单的接口
外观(Facade)提供了一种访问特定子系统功能的便捷方式, 其了解如何重定向客户端请求,知晓如何操作一切活动部件
创建附加外观(Additional Facade)类可以避免多种不相关 的功能污染单一外观,使其变成又一个复杂结构。客户端和 其他外观都可使用附加外观
复杂子系统(Complex Subsystem)由数十个不同对象构成。 如果要用这些对象完成有意义的工作,你必须深入了解子系 统的实现细节,比如按照正确顺序初始化对象和为其提供正 确格式的数据
子系统类不会意识到外观的存在,它们在系统内运作并且相 互之间可直接进行交互
客户端(Client)使用外观代替对子系统对象的直接调用
Example
外观
package main
import "fmt"
type WalletFacade struct { account *Account wallet *Wallet securityCode *SecurityCode notification *Notification ledger *Ledger }
func newWalletFacade(accountID string, code int) *WalletFacade { fmt.Println("Starting create account") walletFacacde := &WalletFacade{ account: newAccount(accountID), securityCode: newSecurityCode(code), wallet: newWallet(), notification: &Notification{}, ledger: &Ledger{}, } fmt.Println("Account created") return walletFacacde }
func (w *WalletFacade) addMoneyToWallet(accountID string, securityCode int, amount int) error { fmt.Println("Starting add money to wallet") err := w.account.checkAccount(accountID) if err != nil { return err } err = w.securityCode.checkCode(securityCode) if err != nil { return err } w.wallet.creditBalance(amount) w.notification.sendWalletCreditNotification() w.ledger.makeEntry(accountID, "credit", amount) return nil }
func (w *WalletFacade) deductMoneyFromWallet(accountID string, securityCode int, amount int) error { fmt.Println("Starting debit money from wallet") err := w.account.checkAccount(accountID) if err != nil { return err }
err = w.securityCode.checkCode(securityCode) if err != nil { return err } err = w.wallet.debitBalance(amount) if err != nil { return err } w.notification.sendWalletDebitNotification() w.ledger.makeEntry(accountID, "debit", amount) return nil }
|
适用场景
- 如果你需要一个指向复杂子系统的直接接口,且该接口的功 能有限,则可以使用外观模式
- 子系统通常会随着时间的推进变得越来越复杂。即便是应用 了设计模式,通常你也会创建更多的类。尽管在多种情形中 子系统可能是更灵活或易于复用的,但其所需的配置和样板 代码数量将会增长得更快。为了解决这个问题,外观将会提 供指向子系统中最常用功能的快捷方式,能够满足客户端的 大部分需求
- 如果需要将子系统组织为多层结构,可以使用外观
- 创建外观来定义子系统中各层次的入口。你可以要求子系统 仅使用外观来进行交互,以减少子系统之间的耦合
优缺点
优点
缺点
与其他模式的关系
- 外观为现有对象定义了一个新接口,适配器则会试图运用已 有的接口。适配器通常只封装一个对象,外观通常会作用于 整个对象子系统上
- 当只需对客户端代码隐藏子系统创建对象的方式时,你可以 使用抽象工厂来代替外观
- 享元展示了如何生成大量的小型对象,外观则展示了如何用 一个对象来代表整个子系统
- 外观和中介者的职责类似:它们都尝试在大量紧密耦合的类中组织起合作
- 外观类通常可以转换为单例类,因为在大部分情况下一个外观对象就足够了
- 外观与代理的相似之处在于它们都缓存了一个复杂实体并自 行对其进行初始化。代理与其服务对象遵循同一接口,使得 自己和服务对象可以互换,在这一点上它与外观不同