Фасад — это структурный паттерн, который предоставляет простой (но урезанный) интерфейс к сложной системе объектов, библиотеке или фреймворку.
Кроме того, что Фасад позволяет снизить общую сложность программы, он также помогает вынести код, зависимый от внешней системы в единственное место.
Концептуальный пример
Можно легко недооценить сложность того, что происходит за кулисами, когда вы заказываете пиццу с помощью кредитной карты. В этом процесе участвуют десятки подсистем. Вот их малая часть:
Проверка аккаунта
Проверка PIN-кода
Баланс дебет/кредит
Запись в бухгалтерской книге
Отправка оповещения
В такой сложной системе легко потеряться или что-то сломать, если обращаться с ней неправильно. Для таких случаев и существует паттерн Фасад — он позволяет клиенту работать с десятками компонентов, используя при этом простой интерфейс. Клиенту необходимо лишь ввести реквизиты карты, код безопасности, стоимость оплаты и тип операции. Фасад управляет дальнейшей коммуникацией между различными компонентами без контакта клиента со сложными внутренними механизмами.
walletFacade.go: Фасад
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
}
account.go: Часть сложной подсистемы
package main
import "fmt"
type Account struct {
name string
}
func newAccount(accountName string) *Account {
return &Account{
name: accountName,
}
}
func (a *Account) checkAccount(accountName string) error {
if a.name != accountName {
return fmt.Errorf("Account Name is incorrect")
}
fmt.Println("Account Verified")
return nil
}
securityCode.go: Часть сложной подсистемы
package main
import "fmt"
type SecurityCode struct {
code int
}
func newSecurityCode(code int) *SecurityCode {
return &SecurityCode{
code: code,
}
}
func (s *SecurityCode) checkCode(incomingCode int) error {
if s.code != incomingCode {
return fmt.Errorf("Security Code is incorrect")
}
fmt.Println("SecurityCode Verified")
return nil
}
wallet.go: Часть сложной подсистемы
package main
import "fmt"
type Wallet struct {
balance int
}
func newWallet() *Wallet {
return &Wallet{
balance: 0,
}
}
func (w *Wallet) creditBalance(amount int) {
w.balance += amount
fmt.Println("Wallet balance added successfully")
return
}
func (w *Wallet) debitBalance(amount int) error {
if w.balance < amount {
return fmt.Errorf("Balance is not sufficient")
}
fmt.Println("Wallet balance is Sufficient")
w.balance = w.balance - amount
return nil
}
ledger.go: Часть сложной подсистемы
package main
import "fmt"
type Ledger struct {
}
func (s *Ledger) makeEntry(accountID, txnType string, amount int) {
fmt.Printf("Make ledger entry for accountId %s with txnType %s for amount %d\n", accountID, txnType, amount)
return
}
notification.go: Часть сложной подсистемы
package main
import "fmt"
type Notification struct {
}
func (n *Notification) sendWalletCreditNotification() {
fmt.Println("Sending wallet credit notification")
}
func (n *Notification) sendWalletDebitNotification() {
fmt.Println("Sending wallet debit notification")
}
main.go: Клиентский код
package main
import (
"fmt"
"log"
)
func main() {
fmt.Println()
walletFacade := newWalletFacade("abc", 1234)
fmt.Println()
err := walletFacade.addMoneyToWallet("abc", 1234, 10)
if err != nil {
log.Fatalf("Error: %s\n", err.Error())
}
fmt.Println()
err = walletFacade.deductMoneyFromWallet("abc", 1234, 5)
if err != nil {
log.Fatalf("Error: %s\n", err.Error())
}
}
output.txt: Результат выполнения
Starting create account
Account created
Starting add money to wallet
Account Verified
SecurityCode Verified
Wallet balance added successfully
Sending wallet credit notification
Make ledger entry for accountId abc with txnType credit for amount 10
Starting debit money from wallet
Account Verified
SecurityCode Verified
Wallet balance is Sufficient
Sending wallet debit notification
Make ledger entry for accountId abc with txnType debit for amount 5