如何在Proto多消息类型中复用自定义Getter方法?
1. 先统一Proto里的字段命名
把CarrierDHLSettings的字段名改成和CarrierUPSSettings一致的default_shipment_weight,这样生成的Go结构体字段名会统一成DefaultShipmentWeight,自动生成的基础Getter也会保持一致:
message CarrierUPSSettings { string default_shipment_weight = 1; } message CarrierDHLSettings { string default_shipment_weight = 1; // 统一字段名,替换原来的default_weight }
改完后重新生成pb.go文件,两个结构体都会自带GetDefaultShipmentWeight() string方法,逻辑就是返回自身字段值或者空字符串。
2. 实现带自定义逻辑的Getter
自动生成的pb.go不能手动改,改了下次生成proto会被覆盖,所以我们在单独的Go文件里扩展这两个结构体,用接口和通用函数来避免重复代码。
2.1 定义通用接口
先搞一个接口,规定好我们需要的自定义Getter方法:
type CarrierSettings interface { GetCustomDefaultShipmentWeight(conf Configuration, req Request) string // 把自动生成的基础Getter也加进来,方便通用逻辑处理 GetDefaultShipmentWeight() string }
2.2 抽离通用逻辑成工具函数
把你要的判断逻辑单独写成一个函数,这样两个结构体不用重复写相同代码:
func getDefaultShipmentWeight(settings CarrierSettings, conf Configuration, req Request) string { // 修正原代码里的拼写错误:Descritpion → Description if conf.Description != "" { return conf.Description } if req.Description != "" { return req.Description } // 最后 fallback 到结构体自身的字段值 return settings.GetDefaultShipmentWeight() }
2.3 给两个结构体实现自定义Getter
分别给CarrierUPSSettings和CarrierDHLSettings实现接口里的方法,直接调用上面的通用函数就行:
// UPS设置的自定义Getter func (m *CarrierUPSSettings) GetCustomDefaultShipmentWeight(conf Configuration, req Request) string { return getDefaultShipmentWeight(m, conf, req) } // DHL设置的自定义Getter func (m *CarrierDHLSettings) GetCustomDefaultShipmentWeight(conf Configuration, req Request) string { return getDefaultShipmentWeight(m, conf, req) }
(可选)关于替换自动生成的Getter
如果你一定要替换自动生成的GetDefaultShipmentWeight方法,不推荐这么做——因为每次重新生成pb.go都会覆盖这个方法。真要做的话,只能每次生成后手动恢复,或者自己写protoc插件来自动生成带自定义逻辑的Getter,显然前者麻烦,后者成本高,不如用上面的自定义方法名(比如GetCustomDefaultShipmentWeight)更稳妥,不会和自动生成的方法冲突。
3. 业务代码里怎么用
通过接口统一处理两种承运商设置,不用区分是UPS还是DHL:
func processShipment(settings CarrierSettings, conf Configuration, req Request) { weight := settings.GetCustomDefaultShipmentWeight(conf, req) // 这里写你的业务逻辑 } // 调用示例 upsSettings := &CarrierUPSSettings{DefaultShipmentWeight: "5kg"} dhlSettings := &CarrierDHLSettings{DefaultShipmentWeight: "3kg"} processShipment(upsSettings, conf, req) processShipment(dhlSettings, conf, req)
这样既统一了字段命名,又避免了重复代码,逻辑完全一致。
内容的提问来源于stack exchange,提问作者Maciej Czarnota

