Lua 下的依赖注入
Posted IT老拐瘦
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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();
这种操作实现起来并不复杂,但是对于软件开发确是大大的提高了效率,降低了耦合。因为:
不关心是什么(返回的是哪个class) ,只关心会什么(返回的是interface)
不关心怎么来(如何构造,如何传参),只关心怎么用。
在真正的工程应用中,经常会将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的?",哈哈,因为本拐认为,依赖注入作为架构设计的一种思路,先是了解其来龙去脉再反过来应用到当前环境比较好。 我们从上面的讲述里可以看到,依赖注入,在面向对象语言中,有这么几步要做。
定义接口,实现业务类;
将接口和业务类的对应写在配置文件中;
实现容器操作将业务类构造返回;
但反观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)
https://github.com/yfge/open-tiny-orm
欢迎各位使用/issure/pull request
哈哈,写了这么多就为推荐ORM么? 被自己的心机陶醉了 :)
关于老拐瘦
散养程序猿,野生架构狮
二流搬砖工,三流摄影师
假正经真逗比,装文艺实二逼
啥也不说,扫码关注吧
以上是关于Lua 下的依赖注入的主要内容,如果未能解决你的问题,请参考以下文章
spring练习,在Eclipse搭建的Spring开发环境中,使用set注入方式,实现对象的依赖关系,通过ClassPathXmlApplicationContext实体类获取Bean对象(代码片段
Android Dagger片段可以访问AppModule和ActivityModule依赖关系,但不能访问FragmentModule依赖关系