【golang】实现依赖注入

依赖注入

    • 一、控制反转是什么?
      • 1、如何理解 Ioc 呢?
      • 2、控制反转和依赖注入
      • 3、小总结
    • 二、依赖注入代码实现

   使用过 Java 的一定知道依赖注入这个概念,说到依赖注入就不得不提一下控制反转(IOC),这个两个不是什么复杂的技术,而是一种思想,一种设计模式,接下来我谈下我对这个设计模式的理解,以及如何使用golang实现依赖注入。

一、控制反转是什么?

控制反转即Ioc(后续使用 Ioc 来表述控制反转),Ioc意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。

1、如何理解 Ioc 呢?

   理解好Ioc的关键是要明确“谁控制谁,控制什么,为何是反转?什么是正转?反转了是为什么什么?带着疑问往下看。

  1. 谁控制谁?
       在程序中,我们直接申明一个对象,是程序主动去创建依赖的对象;Ioc的思想是专门一个容器来创建这些对象,即由Ioc容器来控制对象的创建;Ioc容器控制了对象,控制对象的获取。

  2. 什么是正转?
       说反转之前,先了解下什么是正转,正转顾名思义,程序中由我们自己在对象中主动控制去直接获取依赖对象。

  3. 什么是反转?
       反转即,由容器帮我们查找及注入依赖对象,对象只是被动的接受依赖对象,所以是反转;哪些方面反转了?依赖对象的获取被反转了。

2、控制反转和依赖注入

DI—Dependency Injection,即“依赖注入”(后续使用 DI 来表述依赖注入)

   组件之间依赖关系由容器在运行期决定,形象的说,即由容器动态的将某个依赖关系注入到组件之中。
   通过依赖注入机制,我们只需要通过简单的初始化,而无需任何代码就可指定目标依赖对象,完成自身的业务逻辑,而不需要关心具体的资源来自何处,由谁实现。

  1. 谁依赖谁?
       程序依赖 Ioc 容器
  2. 谁注入谁?
       Ioc 容器注入应用程序某个对象,应用程序依赖的对象
  3. 注入了什么?
       注入某个对象所需要的资源

3、小总结

Ioc 和 DI 是同一个概念的不同角度描述,设计理念是一样的。相对IoC 而言,“依赖注入”明确描述了“被注入对象依赖IoC容器配置依赖对象”。

二、依赖注入代码实现

欢迎点赞、使用、提出改进意见:点击跳转 github,下方讲解核心的实现流程。

  1. 初始化 core.go

    type LoadFunc func(ILoader) error
    var (
    	ErrNotFound = errors.New("key not found")
    	shared      = NewSingleLoader()
    	funcs       = make([]LoadFunc, 0, 16)
    )
    
    func DefaultLoader() ILoader {
    	return shared
    }
    type ILoader interface {
    	Register(key interface{}, value interface{}) error
    	// 加载所有注册变量
    	LoadingAll()
    	// 加载某结构体下变量
    	Loading(v interface{})
    }
    
    // 注册 注册方法
    func Register(f LoadFunc) {
    	funcs = append(funcs, f)
    }
    
    // 将 core 的 funcs 保存的注册方法
    // 全局注入到 loader 的集合中
    func LoadingAll(loader ILoader) (err error) {
    	for _, f := range funcs {
    		err = f(loader)
    		if err != nil {
    			return err
    		}
    	}
    	loader.LoadingAll()
    	return
    }
    
    
  2. 初始化 single.go

    var _ ILoader = new(singleLoader)
    
    // 初始化单例装载器
    func NewSingleLoader() ILoader {
    	return &singleLoader{
    		objs: make(map[interface{}]reflect.Value),
    	}
    }
    
    // 全局 Ioc容器
    type singleLoader struct {
    	objs map[interface{}]reflect.Value
    }
    
    func (s *singleLoader) Register(key interface{}, value interface{}) error {
    	_, ok := s.objs[key]
    	if ok {
    		return errors.New(fmt.Sprintf("key duplicate: %v", key))
    	}
    	s.objs[key] = reflect.ValueOf(value)
    	return nil
    }
    func (s *singleLoader) LoadingAll() {
    	for _, v := range s.objs {
    		s.Loading(v)
    	}
    }
    
    // 装载结构体中依赖的字段
    func (s *singleLoader) Loading(v interface{}) {
    	var value reflect.Value
    	var ok bool
    	if value, ok = v.(reflect.Value); !ok {
    		value = reflect.ValueOf(v)
    	}
    loop:
    	for {
    		switch value.Kind() {
    		case reflect.Ptr:
    			value = value.Elem()
    		case reflect.Interface:
    			value = value.Elem()
    		default:
    			break loop
    		}
    	}
    
    	if value.Kind() != reflect.Struct {
    		return
    	}
    	for i := 0; i < value.NumField(); i++ {
    		name := value.Type().Field(i).Tag.Get(LoaderTag)
    		temp, ok := s.objs[name]
    		if ok {
    			field := value.Field(i)
    			if field.CanSet() {
    				field.Set(temp)
    			} else {
    				field = reflect.NewAt(field.Type(), unsafe.Pointer(field.UnsafeAddr())).Elem()
    				field.Set(temp)
    			}
    		}
    	}
    

你可能感兴趣的:(golang,golang,依赖注入,ioc)