模板模式是一种行为设计模式,它定义了一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板模式使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。

在 Go 中,模板模式通常通过定义一个抽象基类来实现,该类定义了算法的骨架,并将一些可变的方法留给子类来实现。

以下是一个使用模板模式的示例,假设我们有一个简单的日志系统,需要在日志信息中添加时间戳。我们可以使用模板模式来定义一个抽象日志记录器,它定义了一个记录日志的算法骨架,而将时间戳的生成留给具体的子类实现。

首先,我们定义一个抽象日志记录器 LogRecorder,它有一个记录日志的方法 RecordLog,该方法定义了一个日志记录的算法骨架,它包括生成时间戳、记录日志、以及输出日志等步骤:

type LogRecorder interface {
    RecordLog(msg string)
}

type BaseLogRecorder struct{}

func (r *BaseLogRecorder) RecordLog(msg string) {
    timestamp := r.GenerateTimestamp()
    logMsg := fmt.Sprintf("[%s] %s", timestamp, msg)
    r.Log(logMsg)
    r.Output(logMsg)
}

func (r *BaseLogRecorder) GenerateTimestamp() string {
    return time.Now().Format("2006-01-02 15:04:05")
}

func (r *BaseLogRecorder) Log(msg string) {
    // 留给子类实现
}

func (r *BaseLogRecorder) Output(msg string) {
    // 留给子类实现
}

在上述代码中,我们定义了一个抽象基类 BaseLogRecorder,它实现了一个 RecordLog 方法,该方法定义了日志记录的算法骨架,包括生成时间戳、记录日志和输出日志等步骤。GenerateTimestamp 方法用于生成时间戳,Log 方法和 Output 方法留给子类实现。

接下来,我们可以定义一个具体的日志记录器 FileLogRecorder,它继承自 BaseLogRecorder 并实现 Log 和 Output 方法:

type FileLogRecorder struct {
    filename string
}

func NewFileLogRecorder(filename string) *FileLogRecorder {
    return &FileLogRecorder{filename}
}

func (r *FileLogRecorder) Log(msg string) {
    f, err := os.OpenFile(r.filename, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
    if err != nil {
        panic(err)
    }
    defer f.Close()

    if _, err := f.WriteString(msg + "\n"); err != nil {
        panic(err)
    }
}

func (r *FileLogRecorder) Output(msg string) {
    fmt.Println(msg)
}

在上述代码中,我们定义了一个具体的日志记录器 FileLogRecorder,它继承自 BaseLogRecorder 并实现 Log 和 Output 方法。Log 方法将日志记录到文件中,Output 方法将日志输出到控制台中。我们也可以定义其他类型的日志记录器,只需继承 BaseLogRecorder 并实现相应的方法即可。

接下来,我们定义一个 LogRecorderFactory 工厂类,用于根据不同的日志类型创建相应的日志记录器:

type LogRecorderFactory struct{}
func (factory *LogRecorderFactory) CreateLogRecorder(logType string) LogRecorder { 
switch logType { 
case "file": 
return &FileLogRecorder{} 
case "console": 
return &ConsoleLogRecorder{} 
default: return nil 
} 
}

在上述代码中,我们定义了一个 CreateLogRecorder 方法,它接收一个字符串类型的参数 logType,根据不同的 logType 返回相应的日志记录器。如果 logType 无效,则返回 nil。

最后,我们可以使用 LogRecorderFactory 创建不同类型的日志记录器并使用它们:

factory := &LogRecorderFactory{}
fileLogRecorder := factory.CreateLogRecorder("file") 
fileLogRecorder.Log("This is a file log") 
fileLogRecorder.Output("This is a file log output")
consoleLogRecorder := factory.CreateLogRecorder("console") 
consoleLogRecorder.Log("This is a console log") 
consoleLogRecorder.Output("This is a console log output")

在上述代码中,我们使用 LogRecorderFactory 创建了两个不同类型的日志记录器:FileLogRecorder 和 ConsoleLogRecorder,并分别记录和输出日志信息。由于使用了模板模式,我们可以在不修改代码结构的情况下,轻松添加新的日志记录器类型。