doulangbizhan5160 2017-08-23 16:40 采纳率: 100%
浏览 44
已采纳

Golang处理程序处理不同类型

These are AppHandlers from a pattern I found online while researching gorilla/mux. They part of a struct that satisfies http.Handler. If you notice, the following two blocks are exactly the same. Effectively, they could be passed the 'variant' ("flow" or "process") as a string.

func CreateFlow(a *AppContext, w http.ResponseWriter, r *http.Request) (int, error) {

    highest, code, err := a.Create("flow", r)
    if code != 200 || err != nil {
        return code, err
    }

    b := new(bytes.Buffer)
    json.NewEncoder(b).Encode(struct {
        Highest int `json:"id"`
    }{highest})
    w.Header().Set("Content-Type", "application/json")
    w.Write(b.Bytes())
    return 200, nil
}

func CreateProcess(a *AppContext, w http.ResponseWriter, r *http.Request) (int, error) {

    highest, code, err := a.Create("process", r)
    if code != 200 || err != nil {
        return code, err
    }

    b := new(bytes.Buffer)
    json.NewEncoder(b).Encode(struct {
        Highest int `json:"id"`
    }{highest})
    w.Header().Set("Content-Type", "application/json")
    w.Write(b.Bytes())
    return 200, nil
}

However, the following two blocks not only need the string, but they need a variable of the associated type ("Flow" and "Process") to successfully Unmarshal the hit I get from ElasticSearch. Other than that, they are Identical code.

func GetFlow(a *AppContext, w http.ResponseWriter, r *http.Request) (int, error) {

    hit, code, err := a.GetByID("flow", mux.Vars(r)["id"], r)
    if code != 200 {
        return code, err
    }

    var flow Flow

    err = json.Unmarshal(*hit.Source, &flow)
    if err != nil {
        return 500, err
    }

    flow.ESID = hit.Id

    b := new(bytes.Buffer)
    json.NewEncoder(b).Encode(flow)
    w.Header().Set("Content-Type", "application/json")
    w.Write(b.Bytes())
    return 200, nil
}

func GetProcess(a *AppContext, w http.ResponseWriter, r *http.Request) (int, error) {

    hit, code, err := a.GetByID("process", mux.Vars(r)["id"], r)
    if code != 200 {
        return code, err
    }

    var process Process

    err = json.Unmarshal(*hit.Source, &process)
    if err != nil {
        return 500, err
    }

    process.ESID = hit.Id

    b := new(bytes.Buffer)
    json.NewEncoder(b).Encode(process)
    w.Header().Set("Content-Type", "application/json")
    w.Write(b.Bytes())
    return 200, nil
}

I am not sure how to generalize this behavior in golang when there is a declared type involved. These handlers are all in the same package too, as I think that they are all accomplishing a similar task. I am very clearly repeating myself in code but I need advice on how I can improve. I've gone past "a little copying is better than a little dependency." but I am afraid because "reflection is never clear".

Here is an example of the declaration in main using one of these functions.

api.Handle("/flow/{id:[0-9]+}", handlers.AppHandler{context, handlers.GetFlow}).Methods("GET")
  • 写回答

2条回答 默认 最新

  • dqsong2010 2017-08-23 16:48
    关注

    You can do it by passing in an exemplar of the necessary type, the same way that Unmarshal does it:

    func GetFlow(a *AppContext, w http.ResponseWriter, r *http.Request) (int, error) {
        return GetThing(a,w,r,"flow",new(Flow))
    }
    
    func GetProcess(a *AppContext, w http.ResponseWriter, r *http.Request) (int, error) {
        return GetThing(a,w,r,"process",new(Process))
    }
    
    func GetThing(a *AppContext, w http.ResponseWriter, r *http.Request, t string, ob Elastible{}) (int, error) {
        hit, code, err := a.GetByID(t, mux.Vars(r)["id"], r)
        if code != 200 {
            return code, err
        }
    
        err = json.Unmarshal(*hit.Source, ob)
        if err != nil {
            return 500, err
        }
    
        ob.SetESID(hit.Id)
    
        b := new(bytes.Buffer)
        json.NewEncoder(b).Encode(ob)
        w.Header().Set("Content-Type", "application/json")
        w.Write(b.Bytes())
        return 200, nil
    }
    
    type Elastible interface {
        SetESID(id ESIDType)    // whatever type ESID is, not clear from example
    }
    
    func (f *Flow) SetESID(id ESIDType) {
        f.ESID = id
    }
    

    This code is untested (because I don't have your struct defs or other dependent code) but I hope it gets the idea across.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 Python时间序列如何拟合疏系数模型
  • ¥15 求学软件的前人们指明方向🥺
  • ¥50 如何增强飞上天的树莓派的热点信号强度,以使得笔记本可以在地面实现远程桌面连接
  • ¥15 MCNP里如何定义多个源?
  • ¥20 双层网络上信息-疾病传播
  • ¥50 paddlepaddle pinn
  • ¥20 idea运行测试代码报错问题
  • ¥15 网络监控:网络故障告警通知
  • ¥15 django项目运行报编码错误
  • ¥15 STM32驱动继电器