go语言 共同功能 函数 封装与继承 问题
不是很明白题主卡在哪里了,Go 也可以强转一下的啊type Con interface {\tWriteResponse(byte)\t// 以及其他 Con 都有的信息接口}type MessageHandler interface {\tOnMessage(Con, byte)}type IOCon struct {\tSvr MessageHandler\t// 其他实现}func (ic *IOCon) Run() {\t// 实现跟原来一样}func (ic *IOCon) WriteResponse(b byte) {\t// 写到 rps}type SessionCon struct {\tIOCon\tSessiongID string}func (h *sessionMessageHandler) OnMessage(c Con, msg byte) {\t// 如果内部设计假设是此时 Con 一定是 SessionCon, 不要 "处理" 错误。\tsc := c.(*SessionCon) // 该干嘛干嘛}而且这样很容易将 Con 换成个 mock 做 MessageHandler 测试(所以 SessionCon 也经常会是个 interface 而不是 struct.不过我觉得题主这个实例的问题不在复用代码,而是在如何传递带外信息。题主要的 CustomData, Go 是由标准实现的:https://golang.org/pkg/context/,它的主业是控制超时和事务资源管理,在其中传递像 SessionID, AuthToken 之类是很常见的用法。 参考 Go Concurrency Patterns: Context. 各种网络处理都应该带上 context. 例如 http.Handler 的接口,它的 context 在 request 里,但是直接放成参数也很常见。另外如果 Con 接口很多,最好拆一拆,只给 handler 暴露 ResponseWriter, 参考 Go Proverbstype ResponseWriter interface { WriteResponse(byte)}type MessageHandler interface { Handle(context.Context, byte, ResponseWriter)}// IOCon 有超时控制func (ic *IOCon) Run(ctx context.Context) { ctx, cancel = context.WithTimeout(ctx, ic.Timeout) defer cancel() // call Handler 时带上 ctx}const SessionIDKey = "SessionID"// SessionCon 会夹带私货func (sc *SessionCon) Run(ctx context.Context) { ctx = context.WithValue(ctx, SessionIDKey, sc.SessionID) sc.IOCon.Run(ctx)}func (h *sessionMessageHandler) Handle(ctx Context, request byte, response ResponseWriter) { sessionID := ctx.Value(SessionIDKey).(string)}这样做测试比也比上面更简单, 往 context 里塞内容丢进去就好了,没复杂到那个程度时不用搞那么多有的没的 interface.
■网友
有一种做法,是利用接口强大的inferface{}接口,可以明两个接口IoConIface和SessionConIface,其中SessionConIface联合了IoConIface接口,变更ReadMsg方法为ReadMsg(c IoConIface),在ReadMsg内部可以判断,c 是否实现接口 SessionConIface,如果实现则可以读取到SessionId执行SessionId相关的新逻辑,否者执行旧逻辑。具体Demo代码如下:type IoConIface interface {\tRead()\tWrite()}type SessionConIface interface {\tIoConIface\tGetSessionID() int}type IoCon struct {}func (c *IoCon) Read() {\t//read 操作实现代码}func (c *IoCon) Write() {\t//write 操作实现代码}func (c *IoCon) ReceiveLoop() {\tfor {\t\tReadMsg(c)\t}}type SessionCon struct {\tIoCon\tSessionID int}func (c *SessionCon) ReceiveLoop() {\tfor {\t\tReadMsg(c)\t}}func (c *SessionCon) GetSessionID() int {\treturn c.SessionID}func ReadMsg(c IoConIface) {\tif iface, ok := c.(SessionConIface); ok {\t\tSessionId := iface.GetSessionID()\t\tc.Read()\t\t_ = SessionId\t} else {\t\tc.Read()\t}}这种办法在Go的内核很多对地方用到,只要你注意你就会发现,自我觉得比较清晰。Go虽然没有真正意义上的继承,但是Go的联合功能也很强大,能实现interface的联合,和struct的联合,一般OOP的实现思路,它都能实现,除了实现OOP内的多态,比较复杂外。
推荐阅读
- 书屋|江苏启东汇龙镇“一屋多用”聚人气 添功能 增活力
- OC为何跌出语言榜前十
- 王者荣耀李白能不能出肉
- 知乎有没有必要增加一个特别关注功能
- dart这编程语言现在发展怎么样了,语法与Java,c#很相似,甚至更简洁
- 汽车|多项功能进行优化 吉利星瑞推出第二次FOTA升级
- 人民车市|新语言、新起点,捷达VS7 强势入局
- 环球车讯网|丰田奕泽到店实拍,配多功能方向盘,14.58万起,搭2.0L+CVT
- |美感与功能兼顾 特斯拉首席设计师访谈
- C语言 指针引用数组的地址问题
