如何使用Golang中的指针模拟工厂模式_Golang指针与设计模式实践

5次阅读

go中工厂模式应返回接口而非指针,通过指针接收者实现接口以支持方法调用和避免大结构体拷贝,关键在于接口+指针的松耦合设计,而非单纯使用指针。

如何使用Golang中的指针模拟工厂模式_Golang指针与设计模式实践

为什么不能直接用指针实现“工厂模式”

Go 语言没有类、继承构造函数,所谓“工厂模式”在 Go 里本质是函数返回结构体实例(或其指针),而非模拟面向对象的抽象工厂。用 *T 本身不构成模式,关键在于如何封装创建逻辑、解耦使用者与具体类型。强行用指针做“多态基类”反而容易写出难以维护的代码——比如定义一个空接口指针作为“产品基类”,再靠类型断言分发,这既丧失编译期检查,又违背 Go 的惯用法。

用指针配合接口才是 Go 工厂的正确姿势

Go 中典型的工厂函数返回的是接口类型,内部 new 出具体结构体并返回其指针(因为多数结构体需要方法集,而值接收者无法修改原值,指针接收者更通用)。重点不在指针本身,而在指针 + 接口组合带来的松耦合。

  • 工厂函数签名应为 func() Productinterface,而非 func() *Product
  • 具体产品类型需实现接口,且方法接收者通常用指针(func (p *Concrete) Do()),否则无法满足接口要求
  • 若产品结构体较大,返回 *T 避免拷贝;若很小(如 type ID int),返回值也无妨
type Service interface {     Start() } 

type HTTPService struct { port string } func (HTTPService) Start() { / ... */ }

func NewService(kind string) Service { switch kind { case "http": return &HTTPService{port: ":8080"} // 返回指针以满足接口 default: return nil } }

避免常见陷阱:nil 指针调用与接口零值

工厂返回接口时,如果内部 new 失败却返回了 nil,调用方直接调用方法会 panic:panic: runtime Error: invalid memory address or nil pointer dereference。这不是指针用错了,而是没处理创建失败的契约。

  • 不要依赖接口变量是否为 nil 来判断有效性——接口变量本身非 nil,但底层 concrete 值可能是 nil
  • 工厂应明确失败路径:返回 (Service, error),或用哨兵值(如 var ErrInvalidKind = errors.New("invalid kind")
  • 若必须返回可空接口,调用方应先做类型断言并判空:if s, ok := factory() .(*HTTPService); ok && s != nil { ... }

什么时候该传入指针参数而不是返回指针

工厂模式关注“创建”,但实际开发中常遇到初始化依赖外部状态的场景。此时不应让工厂函数承担所有依赖组装,而应接受配置指针或选项函数——这是更灵活、更测试友好的做法。

立即学习go语言免费学习笔记(深入)”;

  • 避免工厂函数内部读取全局配置(如 os.Getenv),改为接收 *ConfigOption 函数
  • 例如:func NewService(cfg *Config) Servicefunc NewService() Service 更可控
  • 若配置字段多,用选项模式(Functional Options)更清晰:NewService(WithPort(":3000"), WithTimeout(5*time.Second))

指针在这里只是传递配置的载体,真正决定工厂行为的是设计契约,不是内存地址。

text=ZqhQzanResources