Как я могу уменьшить избыточный код дублирующейся функции в Golang? - PullRequest
1 голос
/ 30 января 2020

У меня есть приложение Rest API для отображения всех данных json в браузере. Пока у меня больше модулей, мой код более избыточен. и сложный.

func UserList(w http.ResponseWriter, r *http.Request) {
    list := []models.User{}
    db.Find(&list)
    json.NewEncoder(w).Encode(list)
}

func ProductList(w http.ResponseWriter, r *http.Request) {
    list := []models.Product{}
    db.Find(&list)
    json.NewEncoder(w).Encode(list)
}

func OrderList(w http.ResponseWriter, r *http.Request) {
    list := []models.Order{}
    db.Find(&list)
    json.NewEncoder(w).Encode(list)
}

Есть ли лучшее решение превратить этот код в одну функцию Пример

func List(w http.ResponseWriter, r *http.Request) {
    list := ??? List of struct here ???
    db.Find(&list)
    json.NewEncoder(w).Encode(list)
}

Ответы [ 3 ]

4 голосов
/ 30 января 2020

вы можете сделать что-то вроде этого:

func List(list interface{}, w http.ResponseWriter, r *http.Request,) {
    db.Find(list)
    json.NewEncoder(w).Encode(list)
}
2 голосов
/ 30 января 2020

Учитывая, что вы звоните db.Find(&list) Я предполагаю, что они имеют общий интерфейс. В этом случае вы можете обернуть вызовы вашего обработчика следующим образом:

func ListHandler(list <YOUR_INTERFACE>) func(w http.ResponseWriter, r *http.Request) {
    return func(w http.ResponseWriter, r *http.Request) {
        db.Find(&list)
        json.NewEncoder(w).Encode(list)
    }
}

В вашем вызове;

http.HandleFunc("/user/list", ListHandler([]models.User{}))
http.HandleFunc("/product/list", ListHandler([]models.Product{}))
http.HandleFunc("/order/list", ListHandler([]models.Order{}))
2 голосов
/ 30 января 2020

Если вы передаете тип модели в качестве параметра запроса, это должно быть сделано (включая обработку ошибок):

func List(w http.ResponseWriter, r *http.Request) {
    var list interface{}
    switch r.FormValue("model") {
    case "user":
        list = new([]models.User)
    case "product":
        list = new([]models.Product)
    case "order":
        list = new([]models.Order)
    default:
        http.Error(w, "invalid type", http.StatusBadRequest)
        return
    }
    if err := db.Find(list); err != nil {
        http.Error(w, "db error", http.StatusInternalServerError)
        return
    }
    if err := json.NewEncoder(w).Encode(list); err != nil {
        log.Printf("json encoding error: %v", err)
    }
}

Другой вариант - создать реестр типов, и даже создание фрагмента может быть с помощью reflect:

var reg = map[string]reflect.Type{
    "user":    reflect.TypeOf((*models.User)(nil)).Elem(),
    "product": reflect.TypeOf((*models.Product)(nil)).Elem(),
    "order":   reflect.TypeOf((*models.Order)(nil)).Elem(),
}

func List(w http.ResponseWriter, r *http.Request) {
    etype := reg[r.FormValue("model")]
    if etype == nil {
        http.Error(w, "invalid type", http.StatusBadRequest)
        return
    }

    list := reflect.New(reflect.SliceOf(etype)).Interface()
    if err := db.Find(list); err != nil {
        http.Error(w, "db error", http.StatusInternalServerError)
        return
    }
    if err := json.NewEncoder(w).Encode(list); err != nil {
        log.Printf("json encoding error: %v", err)
    }
}
...