Event Observer Pattern in Go
Tags: go, tutorial, programming, beginners
Published: 2023-04-18 12:01:53

The Observer - is a behavioral design pattern that allows an object, called the subject, to notify a list of observers or subscribers about any changes to its state. In Go, this pattern can be used to maintain loosely coupled relationships between objects.

## In a nut shell

The Observer Design Pattern is a great way to design a system where an object can notify a set of observers when its state changes. It's especially useful when we want to decouple objects that depend on each other. In Go, this pattern can be used to maintain loosely coupled relationships between objects. This pattern is part of the GoF patterns, which are a set of design patterns described by Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides in their book "Design Patterns: Elements of Reusable Object-Oriented Software".

In the Observer Design Pattern, the subject maintains a list of observers and notifies them when its state changes. The observers register with the subject to receive notifications, and the subject notifies the observers by calling their update method.

## Why do we need it

The Observer Design Pattern is useful in several scenarios, including:

- When there is a one-to-many relationship between objects, and a change to one object requires changes to other objects.
- When an object should be able to notify other objects without making assumptions about who these objects are.
- When an object should be able to notify other objects without knowing anything about them.

## How can it help us

Observer Design Pattern solves several problems, including:

- It reduces the coupling between objects.
- It allows for better separation of concerns.
- It promotes reusable code.

## What to use

Several packages can simplify the implementation of the Observer Design Pattern in Go, including:

### RxGo

[github.com/reactivex/rxgo/v2](https://github.com/reactivex/rxgo/v2) package provides a set of operators to work with observable streams in a similar way to ReactiveX libraries, allowing to easily implement the Observer Design Pattern in Go.

**RxGo** is a Go implementation of ReactiveX, which is a library for composing asynchronous and event-based programs. It provides a set of operators to work with observable streams, which are sequences of events that can be observed by multiple observers. RxGo allows developers to write code that is declarative, composable, and reusable.

Here is an example of how to use RxGo to implement the Observer Design Pattern in Go:

```go
package main

import (
	"context"
	"fmt"

	"github.com/reactivex/rxgo/v2"
)

type Observer struct{}

func (o Observer) OnNext(item interface{}) {
	fmt.Printf("Received: %v\\n", item)
}

func (o Observer) OnError(err error) {
	fmt.Printf("Error: %v\\n", err)
}

func (o Observer) OnCompleted() {
	fmt.Println("Done!")
}

func main() {
	observable := rxgo.Just("Hello, dev.to!")
	_ = observable.Subscribe(context.Background(), Observer{})
}

```

In this example, we define an observer `Observer` that implements the `rxgo.Observer` interface. We then create an observable `observable` using the `rxgo.Just` method and subscribe to it using the `Subscribe` method. When the observable emits a value, the observer's `OnNext` method is called with that value. If the observable encounters an error, the observer's `OnError` method is called with that error. Finally, when the observable completes, the observer's `OnCompleted` method is called.

### Go Cloud Pub/Sub

[github.com/google/go-cloud/pubsub](https://github.com/google/go-cloud/pubsub) package provides a set of interfaces and tools to work with publish/subscribe messaging. This package allows easy communication between independent components by decoupling the sender and the receiver.

Go Cloud Pub/Sub is a set of libraries and tools for building cloud-native applications. It provides a set of interfaces and tools to work with publish/subscribe messaging, which allows for easy communication between independent components by decoupling the sender and the receiver.

Here is an example of how to use Go Cloud Pub/Sub to implement the Observer Design Pattern in Go:

```go
package main

import (
	"context"
	"fmt"
	"log"
	"time"

	"github.com/google/go-cloud/pubsub"
)

func main() {
	ctx := context.Background()

	// Create a Pub/Sub topic.
	topic, err := pubsub.OpenTopic(ctx, "dev-to-topic")
	if err != nil {
		log.Fatal(err)
	}

	// Create a Pub/Sub subscription.
	subscription, err := pubsub.OpenSubscription(ctx, "some-subscription")
	if err != nil {
		log.Fatal(err)
	}

	// Publish a message to the topic.
	msg := &pubsub.Message{
		Body: []byte("Hello, dev.to!"),
		Metadata: map[string]string{
			"key": "value",
		},
	}
	if err := topic.Send(ctx, msg); err != nil {
		log.Fatal(err)
	}

	// Receive the message from the subscription.
	ctx, cancel := context.WithTimeout(ctx, time.Second)
	defer cancel()
	receivedMsg, err := subscription.Receive(ctx)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("Received: %s\\n", receivedMsg.Body)

	// Acknowledge the message.
	receivedMsg.Ack()

	// Close the subscription and topic.
	if err := subscription.Shutdown(ctx); err != nil {
		log.Fatal(err)
	}
	if err := topic.Shutdown(ctx); err != nil {
		log.Fatal(err)
	}
}

```

In this example, we create a Pub/Sub topic and subscription using the `pubsub.OpenTopic` and `pubsub.OpenSubscription` methods. We then publish a message to the topic using the `topic.Send` method. Finally, we receive the message from the subscription using the `subscription.Receive` method and acknowledge it using the `msg2.Ack` method.

### Watermill

[github.com/ThreeDotsLabs/watermill](https://github.com/ThreeDotsLabs/watermill) package provides a framework for building event-driven applications. It allows easy communication between independent components by decoupling the sender and the receiver.

Watermill is a Go library for building event-driven applications. It provides a framework for building event-driven applications and allows for easy communication between independent components by decoupling the sender and the receiver.

Here is an example of how to use Watermill to implement the Observer Design Pattern in Go:

```go
package main

import (
	"context"
	"fmt"
	"log"

	"github.com/ThreeDotsLabs/watermill"
	"github.com/ThreeDotsLabs/watermill/message"
)

func main() {
	logger := watermill.NewStdLogger(false, true)

	// Create a new router.
	router, err := message.NewRouter(message.RouterConfig{}, logger)
	if err != nil {
		log.Fatal(err)
	}

	// Create a new publisher.
	publisher, err := message.NewPublisher(message.PublisherConfig{}, logger)
	if err != nil {
		log.Fatal(err)
	}

	// Subscribe to a topic.
	topic := "my-topic"
	subscriber, err := router.AddNoPublisherHandler(
		"my-subscriber",
		topic,
		func(msg *message.Message) error {
			fmt.Printf("Received: %s\\n", msg.Payload)
			return nil
		},
	)
	if err != nil {
		log.Fatal(err)
	}

	// Publish a message to the topic.
	msg := message.NewMessage(watermill.NewUUID(), []byte("Hello, dev.to!"))
	if err := publisher.Publish(topic, msg); err != nil {
		log.Fatal(err)
	}

	// Wait for the message to be processed.
	if err := subscriber.AwaitClose(); err != nil {
		log.Fatal(err)
	}
}

```

In this example, we create a new router and publisher using the `message.NewRouter` and `message.NewPublisher` methods. We then subscribe to a topic using the `router.AddNoPublisherHandler` method and publish a message to the topic using the `publisher.Publish` method. Finally, we wait for the message to be processed using the `subscriber.AwaitClose` method.

## Conclusion

The Observer Design Pattern is a powerful tool that can be used to maintain loosely coupled relationships between objects in Go. By using packages like `github.com/reactivex/rxgo/v2`, `github.com/google/go-cloud/pubsub`, and `github.com/ThreeDotsLabs/watermill`, we can simplify the implementation of this pattern and create reusable, modular code. Happy coding!