Notes: Go Design Patterns - Strategy Pattern
This blog contains the implementation of Strategy design pattern using logger example on console and file
Table of contents
No headings in the article.
Strategy pattern allows change of class or behavior of an object at runtime. Objects with similar functionalities implement a common interface. Now, we pass this interface to methods or other places which use these objects. Now, we don't care what kind of object we are passing, we can have different objects or even change objects in operation during runtime without any hassle.
Let's talk about our example. Here, we want to implement logging, console-based and file-based. Logger
interface contains Log
method, and console-based logging object and file-based logging object implement this method:
type LogToConsole struct{}
func (l *LogToConsole) Log(message string) {
fmt.Println(message)
}
type LogToFile struct{}
func (l *LogToFile) Log(message string) {
f, err := os.OpenFile(logFile, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600)
if err != nil {
panic(err)
}
defer f.Close()
if _, err = f.WriteString(message); err != nil {
panic(err)
}
}
Now we pass Logger
interface as a parameter in checkLogger
function and it executes Log
method without knowing anything about its concrete object.
func checkLogger(message string, logger Logger) {
logger.Log(message)
}
Try running this example to understand better:
package main
import (
"fmt"
"os"
)
const logFile = "log.txt"
type Logger interface {
Log(message string)
}
type LogToConsole struct{}
func (l *LogToConsole) Log(message string) {
fmt.Println(message)
}
type LogToFile struct{}
func (l *LogToFile) Log(message string) {
f, err := os.OpenFile(logFile, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600)
if err != nil {
panic(err)
}
defer f.Close()
if _, err = f.WriteString(message); err != nil {
panic(err)
}
}
func checkLogger(message string, logger Logger) {
logger.Log(message)
}
func main() {
checkLogger("log to file\n", &LogToFile{})
checkLogger("log to console", &LogToConsole{})
}