CODESAMPLE

Facade - Go

Share on:

The Facade pattern provides a simplified interface to a complex subsystem. It defines a high-level interface that hides the intricacies of the underlying components. This makes the subsystem easier to use for clients who don’t need to know the details.

The Go code demonstrates a media player facade. The MediaPlayer struct encapsulates the complex interactions between different media components like Codec, VideoFile, and AudioFile. Clients interact solely with MediaPlayer’s Play() method, hiding the initialization and operation of these components. This implementation leverages Go’s struct composition and method receivers, which are idiomatic for creating such interfaces. Error handling is also included, a common practice in Go.

// main.go
package main

import (
	"fmt"
	"log"
)

// Subsystem components
type Codec interface {
	Decode(data []byte) error
}

type VideoFile struct {
	name string
}

type AudioFile struct {
	name string
}

type VLCCodec struct{}

func (c *VLCCodec) Decode(data []byte) error {
	fmt.Println("Decoding video with VLC codec")
	return nil
}

type MP4AudioCodec struct{}

func (c *MP4AudioCodec) Decode(data []byte) error {
	fmt.Println("Decoding audio with MP4 codec")
	return nil
}

// Facade
type MediaPlayer struct {
	videoFile  *VideoFile
	audioFile  *AudioFile
	videoCodec Codec
	audioCodec Codec
}

func NewMediaPlayer(videoFileName, audioFileName string) *MediaPlayer {
	return &MediaPlayer{
		videoFile:  &VideoFile{name: videoFileName},
		audioFile:  &AudioFile{name: audioFileName},
		videoCodec: &VLCCodec{},
		audioCodec: &MP4AudioCodec{},
	}
}

func (mp *MediaPlayer) Play() error {
	fmt.Println("Playing media...")

	videoData, err := mp.getVideoData()
	if err != nil {
		return fmt.Errorf("error getting video data: %w", err)
	}

	audioData, err := mp.getAudioData()
	if err != nil {
		return fmt.Errorf("error getting audio data: %w", err)
	}

	if err := mp.videoCodec.Decode(videoData); err != nil {
		return fmt.Errorf("error decoding video: %w", err)
	}

	if err := mp.audioCodec.Decode(audioData); err != nil {
		return fmt.Errorf("error decoding audio: %w", err)
	}

	fmt.Println("Media playing successfully.")
	return nil
}

func (mp *MediaPlayer) getVideoData() ([]byte, error) {
	fmt.Printf("Loading video file: %s\n", mp.videoFile.name)
	// Simulate loading video data
	return []byte("video data"), nil
}

func (mp *MediaPlayer) getAudioData() ([]byte, error) {
	fmt.Printf("Loading audio file: %s\n", mp.audioFile.name)
	// Simulate loading audio data
	return []byte("audio data"), nil
}

func main() {
	player := NewMediaPlayer("movie.mp4", "sound.mp3")
	err := player.Play()
	if err != nil {
		log.Fatalf("Failed to play media: %v", err)
	}
}