避免代码重复

时间:2014-11-14 09:13:54

标签: go

我正在尝试编写一个Web应用程序,并努力编写干净的代码。

我有一个控制器来处理传入请求和基本控制器,所有控制器都会借用这些字段。

这是我的基本控制器

type Controller struct {
    Request  *http.Request
    Response http.ResponseWriter

    // Reqeust language
    lang string

    // HTML parts
    Title   string
    body    string
    head    string
    content string
    view    string
    errors  []string
    success []string
}
// And methods followed here
func (self *Controller) renderHeadView() { .....

和我的注册控制器

type Controller struct {
    base.Controller
    user *account
}

func (self *Controller) ServeHTTP(rw http.ResponseWriter, r *http.Request) {

    self.Title = "Sign Up"
    self.Request = r
    self.Response = rw

    self.lang = header.Language(self.Request)
    self.user = &account{lang: self.lang}

    switch self.Request.Method {
    case "GET":
        self.get()
    case "POST":
        if err := self.post(); err != nil {
            self.get()
        } else {
            // If everything was successfully
            return
        }

    }
    self.RenderResponseView()
}

和我的激活控制器

type Controller struct {
    base.Controller
}

func (self *Controller) ServeHTTP(rw http.ResponseWriter, r *http.Request) {

    self.Title = "Activate account"
    self.Request = r
    self.Response = rw
    self.lang = header.Language(self.Request)

    self.RenderResponseView()
}

如您所见,ServeHTTP方法看起来几乎相同。我正在考虑将ServeHTTP移动到基本控制器中,然后提供一种方法来调用特殊工作。为了澄清我的意思,请看下面的代码片段(基本控制器)

func (self *Controller) ServeHTTP(rw http.ResponseWriter, r *http.Request) {

    self.Title = "Activate account"
    self.Request = r
    self.Response = rw
    self.lang = header.Language(self.Request)

    // here would come function for special work
    function()
    self.RenderResponseView()
}

我不知道如何提供此实现。如果有人能给我一些建议,我会很高兴的。

1 个答案:

答案 0 :(得分:5)

要引用的好文章是“Middlewares in Go: Best practices and examples

  

在Go中编写Web应用程序时遇到的第一个代码异味是代码重复   在处理请求之前,我们经常需要记录请求,将应用程序错误转换为HTTP 500错误,对用户进行身份验证等。我们需要为每个处理程序执行大部分操作。

     

我们可以创建一个带闭包的函数。但是如果我们有这样的多个函数,它将变得像Javascript中的回调意大利面一样糟糕。我们不希望这样。

     

因此我们可以编写一个处理程序并将另一个处理程序传递给它。

loggingHandler(recoverHandler(indexHandler))
  

所以中间件就像func (http.Handler) http.Handler一样   这样我们传递一个处理程序并返回一个处理程序。最后我们有一个处理程序,可以使用http.Handle(pattern, handler)

进行调用

爱丽丝

  

Alice is a small package to chain handlers more elegantly。此外,我们可以创建一个公共的处理程序列表,并为每条路径重用它们,如下所示:

func main() {
  commonHandlers := alice.New(loggingHandler, recoverHandler)
  http.Handle("/about", commonHandlers.ThenFunc(aboutHandler))
  http.Handle("/", alice.New(commonHandlers, bodyParserHandler).ThenFunc(indexHandler))
  http.ListenAndServe(":8080", nil)
}
  

问题解决了。我们现在有一个惯用的中间件系统,并使用标准接口。 Alice是50行代码,所以它是一个非常小的依赖。