避免代码重复

huangapple go评论89阅读模式
英文:

Avoiding code duplication

问题

我正在尝试编写一个网络应用程序,并努力编写清晰的代码。

我有一个用于处理传入请求的控制器,以及所有控制器都将借用其字段的基本控制器。

这是我的基本控制器:

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

    // 请求语言
    lang string

    // HTML 部分
    Title   string
    body    string
    head    string
    content string
    view    string
    errors  []string
    success []string
}
// 这里是后续的方法
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 {
            // 如果一切顺利
            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)
    
    // 这里将会是特殊工作的函数
    function()
    self.RenderResponseView()
}

我不知道如何实现这一点。如果有人能给我一些建议,我会非常高兴。

英文:

I am trying to write a web application and given the effort to write clean code.

I have a controller for handle incoming request and base controller that all controller will borrow the fields.

This is my base controller

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() { .....

and my sign up controller

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()
}

and my activate controller

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()
}

As you can see, the ServeHTTP method looks pretty much the same. I am thinking of to move ServeHTTP into base controller and then provide an method to call for special work. To clarify what I mean look at the following code snippet(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)
    
    // here would come function for special work
    function()
	self.RenderResponseView()
}

I have no idea how to provide this implementation. I would be very happy, if someone could give me some suggestions.

答案1

得分: 5

一个很好的参考文章是《Go中的中间件:最佳实践和示例》。

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

我们可以创建一个带有闭包的函数。但是如果我们有多个类似的函数,它将变得像JavaScript中的回调地狱一样糟糕。我们不希望出现这种情况。

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

loggingHandler(recoverHandler(indexHandler))

因此,中间件将是类似于func (http.Handler) http.Handler的东西。
这样我们传递一个处理程序并返回一个处理程序。最后,我们只有一个处理程序,并且可以使用http.Handle(pattern, handler)来调用它。


Alice

Alice是一个更加优雅地链接处理程序的小包。此外,我们可以创建一个常见的处理程序列表,并在每个路由中重用它们,像这样:

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行代码,所以它是一个非常小的依赖项。

英文:

A good article to refer to is "Middlewares in Go: Best practices and examples"

> The first code smell we encounter when writing a web application in Go is code duplication.
Before processing the request, we will often need to log the request, convert app errors into HTTP 500 errors, authenticate users, etc. And we need to do most of these things for each handler.

> We could create a function with a closure. But if we have multiple functions like that, it will become as bad as callback spaghetti in Javascript. We don't want that.

> So we can write a handler and pass another handler to it.

loggingHandler(recoverHandler(indexHandler))

> So a middleware would be something like func (http.Handler) http.Handler
This way we pass a handler and returns a handler. At the end we have one handler and can be called with http.Handle(pattern, handler)


Alice

> Alice is a small package to chain handlers more elegantly. Furthermore, we can create a common list of handlers and reuse them for each route like this:

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)
}

> Problem solved. We now have a middleware system that is idiomatic and use standard interfaces. Alice is 50 lines of code, so it is a very small dependency.

huangapple
  • 本文由 发表于 2014年11月14日 17:13:54
  • 转载请务必保留本文链接:https://go.coder-hub.com/26926488.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定