【发布时间】:2017-08-22 07:36:21
【问题描述】:
这里是新的 Gopher,来自 Java 大陆。
假设我有一个通用的存储接口:
package repositories
type Repository interface {
Get(key string) string
Save(key string) string
}
我通过在单独的包中实现此接口来支持多个不同的后端(Redis、Boltdb 等)。但是,每个实现都有需要传入的唯一配置值。所以我在每个包中定义了一个构造函数,类似于:
package redis
type Config struct {
...
}
func New(config *Config) *RedisRepository {
...
}
和
package bolt
type Config struct {
...
}
func New(config *Config) *BoltRepository {
...
}
main.go 读取一个类似于以下内容的 json 配置文件:
type AppConfig struct {
DatabaseName string,
BoltConfig *bolt.Config,
RedisConfig *redis.Config,
}
根据DatabaseName 的值,应用程序将实例化所需的存储库。做这个的最好方式是什么?我在哪里做?现在我正在做某种可怕的 factoryfactory 方法,它看起来很像 Go 的反模式。
在我的 main.go 中,我有一个函数可以读取上述反映的配置值,根据 DatabaseName 的值选择正确的配置(BoltConfig 或 RedisConfig):
func newRepo(c reflect.Value, repoName string) (repositories.Repository, error) {
t := strings.Title(repoName)
repoConfig := c.FieldByName(t).Interface()
repoFactory, err := repositories.RepoFactory(t)
if err != nil {
return nil, err
}
return repoFactory(repoConfig)
}
在我的repositories 包中,我有一个工厂,它查找存储库类型并返回一个生成实例化存储库的工厂函数:
func RepoFactory(provider string) (RepoProviderFunc, error) {
r, ok := repositoryProviders[provider]
if !ok {
return nil, fmt.Errorf("repository does not exist for provider: %s", r)
}
return r, nil
}
type RepoProviderFunc func(config interface{}) (Repository, error)
var ErrBadConfigType = errors.New("wrong configuration type")
var repositoryProviders = map[string]RepoProviderFunc{
redis: func(config interface{}) (Repository, error) {
c, ok := config.(*redis.Config)
if !ok {
return nil, ErrBadConfigType
}
return redis.New(c)
},
bolt: func(config interface{}) (Repository, error) {
c, ok := config.(*bolt.Config)
if !ok {
return nil, ErrBadConfigType
}
return bolt.New(c)
},
}
综合起来,我的main.go 看起来像:
cfg := &AppConfig{}
err = json.Unmarshal(data, cfg)
if err != nil {
log.Fatalln(err)
}
c := reflect.ValueOf(*cfg)
repo, err := newRepo(c, cfg.DatabaseName)
if err != nil {
log.Fatalln(err)
}
是的,在我输入完这段代码的那一刻,我为自己带入这个世界的恐怖而退缩了。有人可以帮我逃离这个工厂地狱吗?做这种事情的更好方法是什么 - 即在运行时选择接口实现。
【问题讨论】:
-
这个问题最初出现是因为我有一个周期性依赖 - 非常有用的链接伙计们,谢谢。
标签: go