结构型模式-外观模式

外观模式

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

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

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

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

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

  4. 客户端(Client)使用外观代替对子系统对象的直接调用

Example

外观

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
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. 如果需要将子系统组织为多层结构,可以使用外观
  • 创建外观来定义子系统中各层次的入口。你可以要求子系统 仅使用外观来进行交互,以减少子系统之间的耦合

优缺点

优点

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

缺点

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

与其他模式的关系

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