以前接触过的一个 Java 项目,实现了一种在我看来很新的做法:

  1. 代码生成的协议类,里面自带了一个未实现的 process 方法
public class Echo extend Msg {
	String msg;
  	public void decode(){}
  	public void encode(){}
  	public void process() throws Exception {
  		throw new UnsupportedOperationException();
  	}
}
  1. 代码生成的协议处理类,格式是这样的
@MsgProcess
public static boolean process(Echo echo) {
	return true;
}
  1. 框架启动的时候,会反射获取到注解@MsgProcess的 Metchod 和他的参数,然后用 javaassist 的字节码操作,将协议类Echoprocess方法给替换掉!这样框架层调用协议的msg.process()就可以直接执行业务逻辑!

Java 写了 10 年,一说起框架,自然想到的就是各种设计模式抽象继承与反射之类,当写 Go 的时候,也受到影响,我现在想用 Go 实现类似的操作,实践的效果如下

  1. 代码生成了 Echo 协议类
package proto
type Echo struct {
	BaseMsg
	Msg string
}
func (msg *Echo) Decode(src *bytes.Buffer) error {}
func (msg *Echo) Encode(dst *bytes.Buffer) error {}
func (msg *Echo) Process() {
	panic("implement me")
}
  1. 代码生成了业务逻辑类
package logic
import proto
func ProcessEcho(msg *proto.Echo) {}
  1. 使用 ast/parser 将Echoprocess的方法体替换为ProcessEcho
func (msg *Echo) Process() {
	logic.ProcessEcho(msg)
}

但重新生成的 Echo 类,有一些问题,首先生成出来的文件,我将其保存为echo_override.go放在另一个 package ,相关的 import 都可能有问题,然后Processimport 了 logic ,而 logic 自然要 import echo ,非常经典的 import cycle 。

这是第一步遇到的问题,我打算先用 interface 解决看看,为什么不用 func 替换,我觉得好丑啊!各位 Go 大神有没有什么建议?我这种思路,符合 Go 的设计哲学吗?

举报· 3353 次点击
登录 注册 站外分享
31 条回复  
HiShan 小成 2024-12-6 15:04:20
奇怪,咋这么多人把自己菜说是被 Java 毒害。。。。
kuanat 小成 2024-12-6 14:56:45
至于是不是符合 Go 哲学的问题,我看不出这样做的意义。正常使用接口就可以了。
NessajCN 小成 2024-12-6 14:51:57
@assiadamo 譬如我现在定义两个 struct, 或者按你的说法是协议 type EncStr struct { Raw string Encoded string } type DecStr struct { Encrypted string Decoded string } 我要在业务里 Process 他俩,譬如打印出人能看到的信息,也就是在 EncStr 里的 Raw 或 DecStr 里的 Decoded 那我在业务里先定义一个 interface type Protocol interface { Print() } 再定义一个 func Process(p Protocol) { p.Print() } 这时候业务里只有他俩就够了 回到前面定义协议的地方,加上下面的内容 func (e *EncStr)Print() { fmt.Println(e.Raw) } func (d *DecStr) Print() { fmt.Println(d.Decoded) } 然后你在业务里调用 Process 函数就行了 https://go.dev/play/p/IaPb1GktEsS
kuanat 小成 2024-12-6 14:41:20
我有两个想法: - 编译时方案,可以交给外部 preprocessor 当作模板来处理,后续代码生成之后再用 Go 编译,当然这个外部工具也可以用 go 写。目前来看基本上都要用特定的模板写法,而不是 Go 代码。 - 运行时方案,理论上这个需求和 hot reloading 应该差不多,对于 JIT 来说是比较好实现的,对于 Go 应该比较难。像 C 没有 runtime 是可以做到的,如果 Go 要实现类似的功能我估计需要魔改 runtime 才行。
assiadamo 楼主 小成 2024-12-6 14:40:42
@povsister 因为以前用过这样的框架,觉得用起来非常爽,现在也算是体验到了框架开发者的心情
securityCoding 初学 2024-12-6 14:39:43
注入一个 process interface 就好了...
povsister 小成 2024-12-6 14:39:10
@assiadamo #23 你这才叫毒瘤… 改 go generate 代码真不是碳基生物能想的活,不要滥用 generate 和开发脚手架。
assiadamo 楼主 小成 2024-12-6 14:33:52
@NessajCN 我理解一下,如果有代码例子就更好了
assiadamo 楼主 小成 2024-12-6 14:33:09
@povsister 我预想的使用方式是开发者定义好协议,这个协议可能带 package 信息,然后 go generate ,所有的模板都生成好了,开发者只需要打开一个生成的 go 文件写业务代码就行
1234下一页
返回顶部