Lua 下的依赖注入

依赖注入是什么?

百度百科有云:

控制反转(Inversion of Control,缩写为IoC),是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。其中最常见的方式叫做依赖注入(Dependency Injection,简称DI),还有一种方式叫“依赖查找”(Dependency Lookup)。通过控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体将其所依赖的对象的引用传递给它。也可以说,依赖被注入到对象中。

面向对象语言里的依赖注入

依赖注入早期是出现在Java中的,因为java的序列化特性,可以将配置存在于xml文件中,使其以 interface => class存放于外部文件。 这样,对于一个工厂来讲,其实现变成了。

public class Factory
{
    public InterfaceA createInterfaceA(){
        string className = this.loadNameOfInterfaceA();//从配置文件读取interfaceA的实现类
        Class info = Class.forName(className);
        Object obj = info.newInstance();
        return (InterfaceA)obj;
    }
}

这样在业务调用里时,进行如下操作:

    Factory factory = new Factory ();
    InterfaceA objA = factory.createInterfaceA();

这种操作实现起来并不复杂,但是对于软件开发确是大大的提高了效率,降低了耦合。因为:

  1. 不关心是什么(返回的是哪个class) ,只关心会什么(返回的是interface)

  2. 不关心怎么来(如何构造,如何传参),只关心怎么用。

在真正的工程应用中,经常会将Factory进一步抽象成容器,将所有的业务对象集中构造,集中返回。而关于具体的配置信息,则保存在专门的配置文件内。

比如PHP/lumen框架中的 functionapp(),就是一个典型的容器方法:

// 得到mysql的连接
$db = app('db');

那么为了达到这个效果,还需要两个步骤:

1. 配置mysql 连接

//config/database.php
return [
    "default"=>[
        "driver"  =>"mysql",
         'host'      => env('DB_HOST', 'localhost'),
            'port'      => env('DB_PORT', 3306),
            'database'  => env('DB_DATABASE', 'forge'),
            'username'  => env('DB_USERNAME', 'forge'),
            'password'  => env('DB_PASSWORD', ''),
            'charset'   => env('DB_CHARSET', 'utf8'),
            'collation' => env('DB_COLLATION', 'utf8_unicode_ci'),
            'prefix'    => env('DB_PREFIX', ''),
            'timezone'  => env('DB_TIMEZONE', '+00:00'),
            'strict'    => env('DB_STRICT_MODE', false),
    ]
];

2. 在系统加载的时候注入配置

$app->singleton('db', function () use ($app) {
    return DB::connection('default');
});

lua 里的依赖注入

看了上面的部分,您肯定会烦,"不是说lua么,怎么一会扯java,一会扯php的?",哈哈,因为本拐认为,依赖注入作为架构设计的一种思路,先是了解其来龙去脉再反过来应用到当前环境比较好。 我们从上面的讲述里可以看到,依赖注入,在面向对象语言中,有这么几步要做。

  1. 定义接口,实现业务类;

  2. 将接口和业务类的对应写在配置文件中;

  3. 实现容器操作将业务类构造返回;

但反观lua,作为并非原生支持面向对象一种脚本语言,我们虽然知道lua中实现面向对象思想的各种方式,但如果为了面向对象而面向对象,是不是有点适得其反了?

一切目的和方法相同的行为都是XX的行为————老拐曰

我们的目的当然不是面向对象,而是依赖注入,那么反观这上面的三条:

1. 定义接口,实现业务类————我们只要实现统的对外接口接即可,如:
insA.lua

local m = {}
function m.say() 
    print 'hello from A'
end
return m 

insB.lua

local m = {}
function m.say() 
    print 'hello from B'
end
return m 

2. 将接口和业务类的对应写在配置文件中————这里我们实现一个统一的配置即可。
config.lua

local insA = require('insA')
local insB = require('insB')
return {
    'say'=insA,
}

3.实现容器操作将业务类构造返回————有了上面两步,我们实现容器就简单的多了。
factory.lua

local cfg = require('config')
local fac = {}
function fac.get_say_ins()
    return cfg['say']
end
return fac

那么在上面的操作做完后,我们顶层就变成了:

local fac = require('factory')
local ins = fac.get_say_ins()
ins.say()

当然,在直接的业务实现中,我们不光要关注具体返回的是哪个实现,还要将对应的初始化参数传入进入。

open-tiny-orm 依赖注入设计

open-tiny-orm 是本拐近期开源的一个小巧的orm,在最近发布的版本里,加入了缓存的实现,那么针对上面聊到的三点,分享一下我的工程做法。

1. 业务实现上,实现了'tiny.cache.shared','tiny.cache.redis','tiny.cache.sync' 三个缓存模块,对外都统一的暴露了 'set','get','del'三个操作缓存的方法。

2. 在配置上,我们约定了如下的配置方式:

    return {
        cache1 = {
            cache_type="redis",
            cache_cfg={
                catlog="user",
                expired=1000,
                redis="default"
                }
            },
        cache2 = {
            cache_type="shared",
            cache_cfg={
                catlog="user",
                expired=10
                }
            },
        cache2 = {
            cache_type = "sync",
            cache_cfg ={
                redis="default",
                catlog="user",
                expired=1000,
                channel="lua:sync:cache",
            }
    }

3. 那么,在约定配置的基础上,我们的fac就变得非常简单粗暴:

local  cache = {
    redis = require('tiny.cache.redis'),
    shared = require('tiny.cache.shared'),
    sync = require('tiny.cache.sync')
}
local cfg = require('tiny.util.cfg')
local M = {}
M._VERSION="1.0"
function M.get(config)
    local cache_cfg = cfg:get_cache_cfg(config)
    local ins = cache[cache_cfg.cache_type]
    if ins ~= nil then
        return ins:new(cache_cfg.cache_cfg)
    end
end
return M 

这里面的cfg是一个辅助的cache读取工具,用于从不同的配置中构造缓存 。

在这个基础上,cache的使用就变非常方便:

local cacheFac = require('tiny.cache')
local str = 'hello word '
local cache = cacheFac.get('cache1')
cache:set (1,str)
local h = cache:get(1)

open-tiny-orm的git地址是:

https://github.com/yfge/open-tiny-orm

欢迎各位使用/issure/pull request

哈哈,写了这么多就为推荐ORM么? 被自己的心机陶醉了 :)

关于老拐瘦

散养程序猿,野生架构狮

二流搬砖工,三流摄影师

假正经真逗比,装文艺实二逼

所以,这么一个公众号里,会有代码,有段子,有美图,有鸡汤,反正,乱七八遭的,没准碰上哪个刚好就烦到您了呢

啥也不说,扫码关注吧

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

拐爷

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值