go语言设计模式-适配器模式
在 Go 语言中,没有像 Java 那样的类和继承,但可以使用结构体嵌套(组合)+ 接口来实现类似的父子类关系,以及抽象方法的效果。
下面我们用 适配器模式(Adapter Pattern) 举例,展示如何在 “父类” 结构体中封装通用逻辑,同时允许子类实现特定逻辑。
什么是适配器模式?
现实中我们经常见到的适配器便是充电器,是因为我们已有的电源接口一般是220V,而我们手机充电一般需要5V电压,所以需要一个适配器让已有的接口适配新的需求。
类比到代码中来,我们已有的功能(Adaptee)可能不完全适配新的需求(Target),但是我们只要加一个适配器(Adapter)做一个转换或者组装,就能复用已有的逻辑,这就是适配器的思想,具体的代码设计如下:
在**适配器模式(Adapter Pattern)**中,关键角色包括:
- 适配者(Adaptee):已有的、原始的类(不兼容当前接口,需要适配)。
- 适配器(Adapter):将适配者封装起来,使其符合目标接口(Target)。
- 目标接口(Target):客户端期望使用的接口。
go实现适配器模式
假设我们有一个日志处理器,不同的日志存储方式(文件、数据库、云存储)需要不同的实现,但大部分逻辑(格式化、时间戳)是通用的。
** 关键设计**
-
LoggerAdapter
(父类/基类):- 封装通用的
Log()
方法,先处理格式化,再调用writeLog()
(抽象方法)。 - 通过结构体嵌套,子类可以复用
LoggerAdapter
的代码。
- 封装通用的
-
FileLogger
、DBLogger
(子类):- 继承
LoggerAdapter
,并实现writeLog()
方法。
- 继承
** Go 代码实现**
package main
import (
"fmt"
"time"
)
// Logger 是适配器接口,子类必须实现 writeLog()
type Logger interface {
Log(message string)
writeLog(formattedMessage string) // "抽象方法"
}
// LoggerAdapter 提供公共方法,并定义 writeLog() 为抽象方法
type LoggerAdapter struct {
Logger // 这里使用接口嵌套,子类必须实现 writeLog()
}
// Log() 是通用方法,子类可以直接复用
func (l *LoggerAdapter) Log(message string) {
// 统一日志格式
formattedMessage := fmt.Sprintf("[%s] %s", time.Now().Format("2006-01-02 15:04:05"), message)
// 调用子类实现的方法
l.writeLog(formattedMessage)
}
// FileLogger 具体适配器,继承 LoggerAdapter
type FileLogger struct {
LoggerAdapter // 继承父类方法
}
// 实现抽象方法 writeLog()
func (f *FileLogger) writeLog(formattedMessage string) {
fmt.Println("📂 写入文件日志:", formattedMessage)
}
// DBLogger 具体适配器,继承 LoggerAdapter
type DBLogger struct {
LoggerAdapter // 继承父类方法
}
// 实现抽象方法 writeLog()
func (d *DBLogger) writeLog(formattedMessage string) {
fmt.Println("🗄️ 写入数据库日志:", formattedMessage)
}
// 主函数测试
func main() {
// 创建 FileLogger
fileLogger := &FileLogger{}
fileLogger.LoggerAdapter.Logger = fileLogger // 让 LoggerAdapter 绑定子类
fileLogger.Log("这是一个文件日志")
// 创建 DBLogger
dbLogger := &DBLogger{}
dbLogger.LoggerAdapter.Logger = dbLogger // 让 LoggerAdapter 绑定子类
dbLogger.Log("这是一个数据库日志")
}
代码解析
-
“父类”
LoggerAdapter
- 提供
Log()
方法,实现通用逻辑(格式化时间、调用writeLog()
)。 writeLog()
定义为 “抽象方法”,由子类实现。- 通过
Logger
接口约束子类必须实现writeLog()
。
- 提供
-
“子类”
FileLogger
、DBLogger
- 继承
LoggerAdapter
,但需要实现writeLog()
逻辑。 FileLogger
写入文件,DBLogger
写入数据库。
- 继承
-
如何调用
- 先创建
FileLogger
/DBLogger
实例。 - 让
LoggerAdapter
绑定子类Logger
接口(即fileLogger.Logger = fileLogger
)。 - 直接调用
Log()
,LoggerAdapter
会自动调用writeLog()
。
- 先创建
适配器模式总结
方式 | Java 继承 | Go 组合 + 接口 |
---|---|---|
继承父类方法 | extends | 结构体嵌套 (LoggerAdapter ) |
抽象方法 | abstract method | 定义接口 + 结构体嵌套 |
子类重写方法 | @Override | 子类实现 writeLog() |
方法调用 | super.method() | 直接 fileLogger.Log() |
Go 推荐使用 “组合优于继承”,所以通过 结构体嵌套 + 接口 实现类似的父子类结构,避免 Java 继承带来的复杂性。
适用场景
- 适配器模式:不同子类有不同实现(如数据库 vs 文件存储)。
- 模板模式:封装通用代码,子类只需要实现特定逻辑。
- 钩子方法:父类提供默认实现,子类可以选择性覆写