0%

golang 抽象工厂模式

前言

golang 显然不是面向对象的语言,也不是面向对象编程。但是面向接口编程却不只是面向对象编程语言的专利,毕竟,接口本质上是一种协议定义,只要实现了这些定义了的协议的对象,都是这种接口类型。

今天想要说的是大型项目都不会直接 New 一个接口,很多人可能没有接触过或者没有仔细研究过。这也非常合理,因为对于大部分的业务代码而言,一个单例模式加一个工厂模式,已经能够 cover 住绝大多数的扩张的场景了。

但是当我在研究 KrakenD 的源码中,我发现了更为可扩展的实践(请原谅我现在的见识短浅吧,我亲爱的读者)

接口

Router 接口只有一个 Run 方法,本质上来说,我们搞一个 工厂函数就可以实现多态的方式。但是一种更佳的实践是使用工厂接口(或者叫抽象工厂模式, 或者说是工厂的工厂)。

例如这里的 Factory 接口, 比如我们的具体实现中有 gin factory, mux factory, 每个 factory 可以持有自己需要的众多对象,并且在 New Router 时,将这些对象赋值给 Router。这就将 Router 依赖的对象从 New Router 时传入,改为了在 New Facotry 时传入。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// Router sets up the public layer exposed to the users
type Router interface {
Run(config.ServiceConfig)
}

// RouterFunc type is an adapter to allow the use of ordinary functions as routers.
// If f is a function with the appropriate signature, RouterFunc(f) is a Router that calls f.
type RouterFunc func(config.ServiceConfig)

// Run implements the Router interface
func (f RouterFunc) Run(cfg config.ServiceConfig) { f(cfg) }

// Factory creates new routers
type Factory interface {
New() Router
NewWithContext(context.Context) Router
}

实现

gin factory

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
type Config struct {
Engine *gin.Engine
Middlewares []gin.HandlerFunc
HandlerFactory HandlerFactory
ProxyFactory proxy.Factory
Logger logging.Logger
RunServer RunServerFunc
}

type factory struct {
cfg Config
}

func NewFactory(cfg Config) router.Factory {
return factory{cfg}
}

mux factory

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
type factory struct {
cfg Config
}

type Config struct {
Engine Engine
Middlewares []HandlerMiddleware
HandlerFactory HandlerFactory
ProxyFactory proxy.Factory
Logger logging.Logger
DebugPattern string
RunServer RunServerFunc
}

// 注意这里的 config 和上面是不一样的
func NewFactory(cfg Config) router.Factory {
if cfg.DebugPattern == "" {
cfg.DebugPattern = DefaultDebugPattern
}
return factory{cfg}
}