几乎在重复自己

Almost Repeating Myself

Combinitorial Explosion You have lots of code that does almost the same thing.. but with tiny variations in data or behavior. This can be difficult to refactor-- perhaps using generics or an interpreter? - Jeff Atwood via Coding Horror

在这种情况下,代码并不多,但它仍然困扰着我。我有一个共同的问题,那就是当尝试连接到一个 IP 时,如果失败,我应该用下一个 IP 重试。

我有一个函数可以为 NSQ 生成生产者:

//Since we are in a critical system, we try with each IP until we get a producer
var err error
for i, success := 0, false; i < len(ips) && !success; i++ {
    publisher, err = nsq.NewProducer(ips[i], nsq.NewConfig())
    if err == nil {
        success = true
    }
}

另一个几乎共享相同代码的函数是接受 NSQ 消费者并连接它的函数:

var err error
for i, success := 0, false; i < len(ips) && !success; i++ {
    err = consumer.ConnectToNSQD(ips[i])
    if err == nil {
        success = true
    }
}

我想在不牺牲易读性的情况下摆脱这段几乎重复的代码。想法?

也许是这样的?

var publisher *nsq.Producer

connectToWorkingIP(ips, func(ip string) error {
    var err error
    publisher, err = nsq.NewProducer(ip, nsq.NewConfig())
    return err
})

connectToWorkingIP(ips, func(ip string) error {
    return consumer.ConnectToNSQD(ip)
})


func connectToWorkingIP(ips []string, f func(string) error) {
    for i, success := 0, false; i < len(ips) && !success; i++ {
        err := f(ips[i])
        if err == nil {
            success = true
        }
    }
}

你搞反了。您的解决方案应该遵循问题的形式,而不是特定解决方案的形式。解决方案中没有任何东西值得重构。它只会增加毫无意义的复杂性。

例如,

package main

import "github.com/nsqio/go-nsq"

// NewProducer is nsq.NewProducer with retries of an address list.
func NewProducer(addrs []string, config *nsq.Config) (producer *nsq.Producer, err error) {
    if len(addrs) == 0 {
        addrs = append(addrs, "")
    }
    for _, addr := range addrs {
        producer, err = nsq.NewProducer(addr, config)
        if err == nil {
            break
        }
    }
    return producer, err
}

// ConnectToNSQD is nsq.ConnectToNSQD with retries of an address list.
func ConnectToNSQD(c *nsq.Consumer, addrs []string) (err error) {
    if len(addrs) == 0 {
        addrs = append(addrs, "")
    }
    for _, addr := range addrs {
        err = c.ConnectToNSQD(addr)
        if err == nil {
            break
        }
    }
    return err
}

func main() {}