结构型模式-外观模式

外观模式

外观是一种结构型设计模式, 能为程序库、框架或其他复杂类提供一个简单的接口

  1. 外观(Facade)提供了一种访问特定子系统功能的便捷方式, 其了解如何重定向客户端请求,知晓如何操作一切活动部件

  2. 创建附加外观(Additional Facade)类可以避免多种不相关 的功能污染单一外观,使其变成又一个复杂结构。客户端和 其他外观都可使用附加外观

  3. 复杂子系统(Complex Subsystem)由数十个不同对象构成。 如果要用这些对象完成有意义的工作,你必须深入了解子系 统的实现细节,比如按照正确顺序初始化对象和为其提供正 确格式的数据

    子系统类不会意识到外观的存在,它们在系统内运作并且相 互之间可直接进行交互

  4. 客户端(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
}

适用场景

  1. 如果你需要一个指向复杂子系统的直接接口,且该接口的功 能有限,则可以使用外观模式
  • 子系统通常会随着时间的推进变得越来越复杂。即便是应用 了设计模式,通常你也会创建更多的类。尽管在多种情形中 子系统可能是更灵活或易于复用的,但其所需的配置和样板 代码数量将会增长得更快。为了解决这个问题,外观将会提 供指向子系统中最常用功能的快捷方式,能够满足客户端的 大部分需求
  1. 如果需要将子系统组织为多层结构,可以使用外观
  • 创建外观来定义子系统中各层次的入口。你可以要求子系统 仅使用外观来进行交互,以减少子系统之间的耦合

优缺点

优点

  • 你可以让自己的代码独立于复杂子系统

缺点

  • 外观可能成为与程序中所有类都耦合的上帝对象

与其他模式的关系

  • 外观为现有对象定义了一个新接口,适配器则会试图运用已 有的接口。适配器通常只封装一个对象,外观通常会作用于 整个对象子系统上
  • 当只需对客户端代码隐藏子系统创建对象的方式时,你可以 使用抽象工厂来代替外观
  • 享元展示了如何生成大量的小型对象,外观则展示了如何用 一个对象来代表整个子系统
  • 外观和中介者的职责类似:它们都尝试在大量紧密耦合的类中组织起合作
  • 外观类通常可以转换为单例类,因为在大部分情况下一个外观对象就足够了
  • 外观与代理的相似之处在于它们都缓存了一个复杂实体并自 行对其进行初始化。代理与其服务对象遵循同一接口,使得 自己和服务对象可以互换,在这一点上它与外观不同