zoukankan      html  css  js  c++  java
  • [原创]20行ruby代码实现依赖注入框架

    我需要依赖注入

    业余时间开发的娱乐项目 (为了练习使用ruby语言)

    遵循SRP原则,业务逻辑拆分由各个service类型提供,假设存在如下几个类型

    • GameService 封装主要游戏业务逻辑
    • UserService 维护用户信息
    • PlayerService 封装当前玩家信息及业务逻辑
    • ChatService 封装聊天业务逻辑

    Service之间存在依赖关系,例如
    PlayerService 依赖 UserService中的方法
    PlayerService 依赖 ChatService中的方法
    GameService 又依赖其他三个Service中的方法

    最佳解决方案,实现依赖注入

    Ruby实现依赖注入 第一版 快速实现

    def init_dependency_injection
      map = {}
    
      Kernel.send :define_method, :get_instance do |clazz|
        instance = map[clazz]
        if instance.nil?
          instance = clazz.new
          map[clazz] = instance
        end
        instance
      end
    end
    

    init_dependency_injection方法在程序入口处调用

    代码解析

    初始化ioc容器 map = {}

    向内核类型中添加扩展方法get_instance(所谓的monkey hook),

    get_instance方法接受参数clazz,表示一个类型,方法中创建该类型对象并添加对象值ico容器中

    PlayerService中如何使用UserService,代码如下

    class PlayerService
      def initialize
        user_service = get_instance(UserService)
        user_service.do_sth
      end
    end
    

    Ruby实现依赖注入 第二版 改进

    我觉得使用上还可以更方便些,类似spring mvc中通过注解进行依赖注入,向Kernal中补充autowired方法

    def init_dependency_injection
      map = {}
    
      Kernel.send :define_method, :get_instance do |clazz|
        instance = map[clazz]
        if instance.nil?
          instance = clazz.new
          map[clazz] = instance
        end
        instance
      end
    
      Kernel.send :define_method, :autowired do |*classes|
        classes.each do |clazz|
          underscore_class_name = clazz.name.to_s.gsub(/(.)([A-Z])/, '1_2').downcase
          instance_variable_set("@#{underscore_class_name}", get_instance(clazz))
        end
      end
    end
    

    使用方式如下

    class PlayerService
      def initialize
        autowired(UserService)
      end
    
      def x
        @user_service.do_sth
      end
    end
    

    对于GameService依赖多个Services,同样简单,如下

    class GameService
      def initialize
        autowired(UserService, PlayerService, ChatService)
      end
      
      def x
        @user_service.do_sth
        @player_service.do_sth
        @chat_service.do_sth
      end
    end
    

    程序中任何类型中,都可以使用autowired方法注入所需类型对象,自动定义实例变量,便于使用

    autowired方法代码解析

    1. 获取类型集合,遍历之
    2. 获取类名,由CamelCase转换为under_score,作为实例变量名
    3. 通过instance_variable_set设置实例变量,值通过get_instance获取

    perfect!

  • 相关阅读:
    顺序链表的实现
    交换排序(冒泡排序与快速排序)
    插入排序及升级版希尔排序
    循环队列的顺序结构实现
    .NET资源泄露与处理方案
    获取某月第一天,最后一天的sql server脚本
    Oracle Net Manager 的使用方法(监听的配置方法)
    如果有人问你数据库原理,叫他看这篇文章
    如何统计一段时间内但不包含周六日的所有日期
    一个技术人的知识管理方法论
  • 原文地址:https://www.cnblogs.com/gods/p/4693499.html
Copyright © 2011-2022 走看看