一、Functional Options Pattern(函数式选项模式)
缘起:知道这个Option是在filecoin-lotus项目代码中,当时感觉不太好懂,但不影响对大局的理解,后来有时间了去深入研究了一下。其实通过一个简单的示例就能理解他是干嘛的了:
package main
import "fmt"
func main(){
config1 := NewConfig()
config1.Print()
config2 := NewConfig(WithHost("192.168.1.1"),WithPort(8088))
config2.Print()
}
type Config struct {
host string
port int
}
func(c *Config)Print(){
fmt.Println("c.host: ",c.host," c.port: ",c.port)
}
type Option func(c *Config)
func WithHost(host string)Option{
return func(c *Config) {
c.host = host
}
}
func WithPort(port int)Option{
return func(c *Config) {
c.port=port
}
}
func NewConfig(opts ...Option)(c *Config){
c = &Config{
host: "127.0.0.1",
port: 8080,
}
for _,opt :=range opts{
opt(c)
}
return c
}
从代码中可以看到,option模式的作用主要是在实例化对象的时候,可以更灵活的传参,可以以任意的顺序传任意部分字段的参数,比如有八个参数,我可以只传0或1或2或……8个参数,且顺序可以是乱序的。很多项目的源码中都有用到option模式,理解他的作用和用法对于阅读项目源码有好处。
二、接口与多态的运用
总的结构是:
1、纲领文件;2、接口文件;3具体实现文件(多个)
//1、纲领文件
var contractOnce sync.Once
var contractTemplate = make(map[int8]TypeEvent)
//每新增一个contract,需要新增一个enum & contractTemplate
const (
WalletType = 1
IncentiveType = 2
)
func EventAllFactory(contractType int8, contractAdd string, client *ethclient.Client, data *types.Log) {
contractOnce.Do(func() {
contractTemplate[WalletType] = new(wallet.Event)
contractTemplate[IncentiveType] = new(incentive.Event)
})
if _, ok := contractTemplate[contractType]; !ok {
return
}
contractTemplate[contractType].PullEvent(contractAdd, client, data)
}
//2、 接口文件
type TypeEvent interface {
PullEvent(contractAdd string, client *ethclient.Client, data *types.Log)
}
//3、具体实现之一
type MintEvent struct{}
func(mintEvent MintEvent)PullEvent(contractAdd string, client *ethclient.Client, data *types.Log){
//todo:logic
}
可以看到纲领文件的作用是用一个map存储各种类型的实现实例,然后根据不同的实例执行其方法,这个map的value可以直接使用接口名。
纲领文件中使用到了sync.Once及其Do方法,这个类似init()方法,只执行一次,但时机是EventAllFactory函数第一次被调用时。
init函数是当文件被加载时执行,仅执行一次
sync.Once当代码需要被执行时执行,仅执行一次
三、常用API,可以背下来:
//获取以太坊地址
var address common.Address = common.HexToAddress("0x000000")
//调用合约方法
callOpt := &bind.CallOpts{
Pending: true,
BlockNumber: blockNumBig,
Context: context.Background(),
}
contractObject.CallContractFunction(callOpt,otherParam)
//想把对象转换为json字符串且字段名首字母小写:
type Vo{
Name string `json:"name"`
Age string `json:"age"`
}
vo := &Vo{"冯宝宝","168"}
jsonResult,err :=json.Marshal(vo)
//java中把冯宝宝还原:
Vo vo = JSON.parseObject(o.toString(), Vo.class);
回顾下java中,存取jsonArray:
存时转为JSONString:
JSON.toJSONString(list)
取时转为原list
JSON.parseObject(object.toString(), new TypeReference<List<SomeVo>>() {})