Wiosenna WYPRZEDAŻ
Fasada

Fasada w języku Go

Fasada to strukturalny wzorzec projektowy wyposażający złożony system klas, bibliotekę lub framework w uproszczony interfejs.

Fasada zmniejsza ogólną złożoność aplikacji oraz pomaga przenieść niechciane zależności w jedno miejsce w programie.

Przykład koncepcyjny

Łatwo można nie docenić złożoności czegoś tak pozornie prostego jak zamawianie pizzy korzystając z karty kredytowej. W procesie tym za kulisami bierze udział multum podsystemów:

  • Sprawdzanie konta
  • Sprawdzanie kodu PIN
  • Sprawdzanie salda konta
  • Księgowanie
  • Wysłanie powiadomienia

W tak skomplikowanym systemie łatwo jest się pogubić i coś zepsuć w razie popełnienia błędu. Z myślą o tym stworzono koncepcję wzorca Fasada: coś, co pozwoli klientowi korzystać z wielu komponentów za pomocą prostego interfejsu. Klient musi jedynie znać szczegóły karty, kod PIN, kwotę do zapłacenia i typ operacji. Fasada zaś pokieruje dalszą komunikacją z poszczególnymi komponentami bez konieczności wtajemniczania klienta w cały proces.

walletFacade.go: Fasada

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: Złożone części podsystemu

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: Złożone części podsystemu

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: Złożone części podsystemu

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: Złożone części podsystemu

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: Złożone części podsystemu

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: Kod klienta

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: Wynik działania

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
Na podstawie: Golang By Example

Fasada w innych językach

Fasada w języku C# Fasada w języku C++ Fasada w języku Java Fasada w języku PHP Fasada w języku Python Fasada w języku Ruby Fasada w języku Rust Fasada w języku Swift Fasada w języku TypeScript