Go 디자인 패턴 : 옵저버



다른 개체(관찰 가능)를 구독하는 개체 그룹(관찰자)을 가질 수 있는 동작 패턴입니다.

일반적으로 관찰자에게 이벤트 발생을 알리는 데 사용됩니다.

고루틴은 이 디자인 패턴을 구현하는 매우 효율적인 방법을 제공합니다.

이 예를 보자.
  • 먼저 관찰 가능한 개체를 구현해야 합니다. 여기에는 관찰자 배열이 있습니다.

  • 이 예에서 우리의 관찰 가능한 객체는 "주제"가 될 것이며 이것은 그의 관찰자에게 제품의 가용성을 알릴 것입니다.

    type Topic struct {
        Observers []Observer
        Name      string
        Available bool
    }
    
    //Constructor
    func NewTopic(name string) *Topic {
        return &Topic{
            Name: name,
        }
    }
    
    //Update 'Available' value and notify it to Observers
    func (i *Topic) UpdateAvailable(value bool) {
        i.Available = value
        i.Broadcast()
    }
    
    //Using Goroutines, will notify each observer of the array
    func (i *Topic) Broadcast() {
        var wg sync.WaitGroup
        for _, obj := range i.Observers {
            wg.Add(1)
            go func(observer Observer) {
                defer wg.Done()
                observer.Notify(i.Name, i.Available)
            }(obj)
        }
        wg.Wait()
    }
    
    //Add a new observer to the array
    func (i *Topic) Register(observer Observer) {
        i.Observers = append(i.Observers, observer)
    }
    
    


  • 그런 다음 우리는 관찰자 개체를 "보이는"방법을 정의해야 합니다. 이 개체는 다른 동작을 가질 수 있습니다. OOP에서는 일반적으로 관찰자에 대한 추상 클래스를 사용하고 Go에서는 각 개체가 구현해야 하는 인터페이스를 사용할 수 있습니다. 관찰자.

  • 이 예에서는 관찰자, EmailClient 및 SMSClient 유형에 존재합니다.

    type Observer interface {
        GetId() string //Id Getter
        Notify(name string, value bool) //Send the notification
    }
    
    type EmailClient struct {
        id string
    }
    
    func (eC *EmailClient) GetId() string {
        return eC.id
    }
    
    func (eC *EmailClient) Notify(name string, value bool) {
    
        if value {
            fmt.Printf("Sending email - %s available to client %s\n", name, eC.id)
        } else {
            fmt.Printf("Sending email - %s not available to client %s\n", name, eC.id)
        }
    
    }
    
    type SMSClient struct {
        id string
    }
    
    func (sC *SMSClient) GetId() string {
        return sC.id
    }
    
    func (sC *SMSClient) Notify(name string, value bool) {
    
        if value {
            fmt.Printf("Sending SMS - %s available to client %s\n", name, sC.id)
        } else {
            fmt.Printf("Sending SMS - %s not available to client %s\n", name, sC.id)
        }
    
    }
    


    코드 실행




    func main() {
        nvidiaTopic := NewTopic("RTX 3080")
        firstObserver := &EmailClient{
            id: "100",
        }
        secondObserver := &SMSClient{
            id: "200",
        }
        nvidiaTopic.Register(firstObserver)
        nvidiaTopic.Register(secondObserver)
        nvidiaTopic.UpdateAvailable(true)
        nvidiaTopic.UpdateAvailable(false)
    }
    


    산출

    Sending SMS - RTX 3080 available to client 200
    Sending email - RTX 3080 available to client 100
    Sending SMS - RTX 3080 not available to client 200
    Sending email - RTX 3080 not available to client 100
    
    Program exited.
    


    전체 예




    package main
    
    import (
        "fmt"
        "sync"
    )
    
    type Topic struct {
        Observers []Observer
        Name      string
        Available bool
    }
    
    //Constructor
    func NewTopic(name string) *Topic {
        return &Topic{
            Name: name,
        }
    }
    
    //Update 'Available' value and notify it to Observers
    func (i *Topic) UpdateAvailable(value bool) {
        i.Available = value
        i.Broadcast()
    }
    
    //Using Goroutines, will notify each observer of the array
    func (i *Topic) Broadcast() {
        var wg sync.WaitGroup
        for _, obj := range i.Observers {
            wg.Add(1)
            go func(observer Observer) {
                defer wg.Done()
                observer.Notify(i.Name, i.Available)
            }(obj)
        }
        wg.Wait()
    }
    
    //Add a new observer to the array
    func (i *Topic) Register(observer Observer) {
        i.Observers = append(i.Observers, observer)
    }
    
    type Observer interface {
        GetId() string                  //Id Getter
        Notify(name string, value bool) //Send the notification
    }
    
    type EmailClient struct {
        id string
    }
    
    func (eC *EmailClient) GetId() string {
        return eC.id
    }
    
    func (eC *EmailClient) Notify(name string, value bool) {
    
        if value {
            fmt.Printf("Sending email - %s available to client %s\n", name, eC.id)
        } else {
            fmt.Printf("Sending email - %s not available to client %s\n", name, eC.id)
        }
    
    }
    
    type SMSClient struct {
        id string
    }
    
    func (sC *SMSClient) GetId() string {
        return sC.id
    }
    
    func (sC *SMSClient) Notify(name string, value bool) {
    
        if value {
            fmt.Printf("Sending SMS - %s available to client %s\n", name, sC.id)
        } else {
            fmt.Printf("Sending SMS - %s not available to client %s\n", name, sC.id)
        }
    
    }
    
    func main() {
        nvidiaTopic := NewTopic("RTX 3080")
        firstObserver := &EmailClient{
            id: "100",
        }
        secondObserver := &SMSClient{
            id: "200",
        }
        nvidiaTopic.Register(firstObserver)
        nvidiaTopic.Register(secondObserver)
        nvidiaTopic.UpdateAvailable(true)
        nvidiaTopic.UpdateAvailable(false)
    }
    


    그게 다야, 다른 게시물에서 만나요.

    좋은 웹페이지 즐겨찾기