什么是可插拔式框架
最早接触可插拔式的框架是python的flask,当时觉得这玩意老牛逼了,任何组件都能替换,你可以用jinja2/mako来做模版引擎,你可以选择SQLAlchemy或者其他orm框架来操作数据库。
思考了很久,pluggable的本质在于可替换。可替换在软件开发处处都可以体现,比如mysql驱动和mysql驱动实现,orm框架和数据库连接池,同样的orm框架,可以使用不同的连接池。而这种可替换在于抽象,golang标准库给我们提供了一套标准的sql操作接口,不同数据库只要实现这个接口。
这样想,pluggable也是离不开抽象的。抽空研究了一下micro的代码,发现,确实如此。
可默认,可替换
1. 默认参数
pluggable
,最直观的理解大概就是“可以替换,不替换也行”。在编码中,很多语言天生有一项能力和这个类似——默认参数:
# python
def test(name="lqczzz"):
print(name)
test() # "lqczzz"
test("jack") # "jack"
这里,name这个变量是可以替换的,某种意义上也可以说是“pluggable”
2. 可选参数 + 默认值
默认参数很方便,golang
没有默认参数,可以通过可选参数和默认值来实现
const DefaultName = "lqczzz"
func test(args ...string) {
name := DefaultName
if len(args) != 0 { name = args[0] }
fmt.Println(name)
}
// 不传参数
test() // "lqczzz"
// 传参数
test("jack") // "jack"
micro的可插拔式的实现本质上也是如此。
// eg:
type iBE interface {
FeatureImpl()
}
type beOption struct {
pm iPM
}
type qczzzl struct {
opts beOption
}
func (qc *qczzzl) FeatureImpl() {
qc.opts.pm.AddFeature()
fmt.Println("qczzzl will implement it!")
}
pm = &defaultPM{}
be = &qczzzl{opts: beOption{pm: pm}}
be.FeatureImpl()
// output:
// zhangiaolong add feature
// qczzzl will implement it!
// 换pm
newPm := &pmLiyunlong{}
be.opts.pm = newPm
be.FeatureImpl()
// output:
// liyunlong add feature
// qczzzl will implement it!
3. 接口
函数式参数
模块的抽象
变化和不变
接口
契约不变
实现方式变化
struct
封装依赖的变化(不变的契约依赖)
封装通用数据(不变的数据依赖)