2.15 Go之工厂模式自动注册

2.15 Go之工厂模式自动注册

什么是自动注册

示例调用:

import "database/sql"
import _ "github.com/go-sql-driver/mysql"

解析:

明明没有使用github.com/go-sql-driver/mysql包却还是需要导入的原因:

这个包是mysql的驱动包,database/sql定义了一些规范,不同实现者可以根据这个规范实现自己的驱动,然后通过 import _ github.com/go-sql-driver/mysql" 将驱动注册到database/sql中。使用者只需要根据database/sql来操作数据库,而不用去关心驱动具体是怎么做的。

原因:

具体在上面的Go包初始化过程当中有讲解到

Goland的自动注册

golang的包如果包含有init函数,那么会在import的时候执行这个函数(在执行main之前执行的init

我们可以利用这个特性,实现自动注册

代码结构:

            clsfactory
          ├── main.go
          └── base
              └── factory.go
          └── cls1
              └── reg.go
          └── cls2
              └── reg.go

factory.go

package base

/* 创建一个接口 */
type Class interface {
   Do()
}

/* 定义一个变量,保存接口注册好的信息 */
var (
   // 保存注册好的工厂信息
   /*
   map的key是字符串,func() Class是一个返回值为Class接口对象的函数作为map的value
   提供给工厂方注册使用,所谓的“工厂”,就是一个定义为func() Class的普通函数,调用此函数,创建一个类实例,实现的工厂内部结构体会实现Class接口
    */
   factoryByName = make(map[string]func() Class)
)

/* 注册器,类生成工厂 */
func Register(name string, factory func() Class) error {
   if "" != name {
       // 设置工厂名称
       factoryByName[name] = factory
  }
   return nil
}

/* 根据名称创建对应的类接口对象 */
func Create(name string) Class {
   if "" != name {
       /*
       在已经注册的信息中查找名字对应的工厂函数,找到后,在下一行调用并返回接口
        */
       if f, ok := factoryByName[name]; ok {
           return f()
      }else {
           panic("未找到该名称!")
      }
  }
   return nil
}

cls1.go

package cls1

import (
   "GoPracticeClsFactory/base"
   "fmt"
)

/*
定义一个结构体
实现base包下的class接口
定义初始化的init()函数
*/

/* 定义一个结构体1 */
type Class1 struct {
}

/* 实现factory下的class接口 */
func (c *Class1) Do() {
   fmt.Println("HelloWorld!")
}

/* 定义init()初始化函数 */
func init() {
   base.Register("Class1", func() base.Class{
       // 闭包写法,具体函数内容在使用时自行定义
       return new(Class1)
  })
}

cls2.go

package cls2

import (
   "GoPracticeClsFactory/base"
   "fmt"
)

/*
定义结构体
实现factory文件下的接口
定义init()方法
*/

/* 定义结构体 */
type Class2 struct {
}

func (c *Class2) Do() {
   fmt.Println("Class2")
}

func init() {
   // 启动注册器自动注册class2工厂--->调用base包下定义的函数
   base.Register("Class2", func() base.Class {
       return new(Class2)
  })
}

main.go文件中进行调用:

package main

/*
调用前面的三个目录下定义文件下的函数
*/
import (
   "GoPracticeClsFactory/base"
)

func main() {
   // 创建c1实例
   c1:= base.Create("Class1")
   // 调用接口下的函数
   c1.Do()

   // 创建c2实例
   c2 := base.Create("Class2")
   c2.Do()
}
posted @ 2022-02-28 10:04  俊king  阅读(422)  评论(0)    收藏  举报