原则
编写代码单元应该少于15行,方便阅读、理解、测试、重构,超过15行应提取拆分,直至少于15行。
应用
下面我们通过例子来应用此原则。原代码如下:
func initEngine() *gin.Engine {
router := gin.Default()
m := melody.New()
m.Config.MaxMessageSize = 10024
m.Config.MessageBufferSize = 5120
Rooms = make(map[string]RoomInfo)
router.GET("/v", func(c *gin.Context) {
m.HandleRequest(c.Writer, c.Request)
})
m.HandleConnect(func(session *melody.Session) {
log.Info("[ws] connect:", session)
})
m.HandleDisconnect(func(session *melody.Session) {
log.Info("[ws] disconnect", session)
})
m.HandleMessage(func(session *melody.Session, msg []byte) {
reg, exists := session.Get("reg")
log.Info("[ws] message:", string(msg), "reg:", reg)
if string(msg) == WebSocketClientBye {
if exists {
sp := (reg).(*WSMessage)
if removeRoom(sp.RoomID, sp.ClientID) != "" {
log.Warnf("Socket removeRoom error:%v", reg)
}
}
log.Info("Socket bye", reg)
return
}
message := &WSMessage{}
err := json.Unmarshal(msg, message)
if err != nil {
log.Error("Json error :", err)
return
}
switch message.CMD {
case "register":
log.Debug("register")
session.Set("reg", message)
return
default:
log.Debug("socket default json:", message)
// check
p := (reg).(*WSMessage)
roomID := p.RoomID
my := p.ClientID
m.BroadcastFilter(msg, func(s *melody.Session) bool {
if reg, exists = s.Get("reg"); exists {
sp := (reg).(*WSMessage)
if r, ok := Rooms[roomID]; ok {
for _, c := range r.Clients {
if (sp.ClientID == c.ClientID) && (c.ClientID != my) {
log.Info("[ws] <----sent---->", c, my, string(msg))
return true
}
}
} else {
log.Warnf("[ws] only myself???? roomID:%d,my:%v,msg:%v", roomID, my, string(msg))
}
}
return false
})
}
})
return router
}
这是一个初始化并实现WebSocket
与Web
功能的服务器,省略部分代码,并删除了一些调试信息。注释少的可怜,如果初次到这样的代码一定会觉得头大。在重构过程中发现使用此原则会让代码结构清晰,这也是我们重构的目的。下面简单介绍使用的方法:
- 揉功能塞到一起了,应该想办法把相同的功能抽离出新的函数。
原代码:
m.BroadcastFilter(msg, func(s *melody.Session) bool { if reg, exists = s.Get("reg"); exists { sp := (reg).(*WSMessage) if r, ok := Rooms[roomID]; ok { for _, c := range r.Clients { if (sp.ClientID == c.ClientID) && (c.ClientID != my) { log.Info("[ws] <----sent---->", c, my, string(msg)) return true } } } else { log.Warnf("[ws] only myself???? roomID:%d,my:%v,msg:%v", roomID, my, string(msg)) } } return false })
重构代码:
// SendRoomBroadcast 发送房间广播 func (wss *WebSocketServer) SendRoomBroadcast(roomID, my string, msg []byte) { wss.Server.BroadcastFilter(msg, func(s *melody.Session) bool { if reg, exists := s.Get("reg"); exists { sp := (reg).(*WSMessage) if r, ok := Rooms[roomID]; ok { for _, c := range r.Clients { if (sp.ClientID == c.ClientID) && (c.ClientID != my) { return true } } } else { log.Warnf("[ws] only myself???? roomID:%d,my:%v,msg:%v", roomID, my, string(msg)) } } return false }) }
- 封装类
当代码整