【问题标题】:A function by type? How refactor it?按类型划分的函数?如何重构它?
【发布时间】:2014-10-21 05:10:59
【问题描述】:

我正在从文件中读取 json 数据并使用 gob 编码将其发送到远程服务器, 但我对我的代码不满意,我尝试了几种方法来获得更通用的函数,但我失败了,我的代码工作的唯一方法是为每种类型提供相同的函数。

我尝试对类型使用 switch,但同样需要重复代码才能解组和编码 gob 数据

请,有人可以帮助我了解如何改进吗?

两种类型:

type Data1 struct{
ID int
Message string
}

type Data2 struct{
 Serial int
 Height float64
 Loss   float64
 Temp   float64
 Oil    float64
}

Data1 类型的函数

func SenderData1(address string, buff *filebuffer.Buffer) {
    var conn net.Conn
    var err error
    var line string
    var obj Data1
    for {
        line, err = buff.Pop()
        if err != nil {
            log.Critical("Error Poping:", err.Error())
            continue
        }
        if len(line) == 0 {
            time.Sleep(1 * time.Second)
            continue
        }
        if err := json.Unmarshal([]byte(line), &obj); err != nil {
            log.Critical("Error Unmarshaling:", err.Error())
            continue
        }
        for {
            log.Info("Trying to connect with Server...")
            conn, err = net.Dial(PROTO, address)
            // If err try to connect again
            if err != nil {
                log.Error("Error connecting:", err.Error())
                time.Sleep(1 * time.Second)
                continue
            }
            // If connected break the loop
            break
        }
        log.Debug("Sending ", obj, " to:", address)

        encoder := gob.NewEncoder(conn)
        err := encoder.Encode(obj)
        if err != nil {
            log.Critical("Error Encoding Gob:", err.Error())
        }
        // Timer between every sending, ie. Reading from buffer
        time.Sleep(300 * time.Millisecond)
        conn.Close()
    }
}

相同的功能,但用于 Data2 类型

func SenderData2(address string, buff *filebuffer.Buffer) {
    var conn net.Conn
    var err error
    var line string
    var obj Data2
    for {
        line, err = buff.Pop()
        if err != nil {
            log.Critical("Error Poping:", err.Error())
            continue
        }
        if len(line) == 0 {
            time.Sleep(1 * time.Second)
            continue
        }
        if err := json.Unmarshal([]byte(line), &obj); err != nil {
            log.Critical("Error Unmarshaling:", err.Error())
            continue
        }
        for {
            log.Info("Trying to connect with Server...")
            conn, err = net.Dial(PROTO, address)
            // If err try to connect again
            if err != nil {
                log.Error("Error connecting:", err.Error())
                time.Sleep(1 * time.Second)
                continue
            }
            // If connected break the loop
            break
        }
        log.Debug("Sending ", obj, " to:", address)

        encoder := gob.NewEncoder(conn)
        err := encoder.Encode(obj)
        if err != nil {
            log.Critical("Error Encoding Gob:", err.Error())
        }
        // Timer between every sending, ie. Reading from buffer
        time.Sleep(300 * time.Millisecond)
        conn.Close()
    }

【问题讨论】:

    标签: go refactoring


    【解决方案1】:

    添加一个参数,为接收和发送分配一个新的类型值:

    func SenderData1(address string, buff *filebuffer.Buffer) {
        SenderData(address, buff, func() interface{} { return new(Data1) })
    }
    
    func SenderData2(address string, buff *filebuffer.Buffer) {
        SenderData(address, buff, func() interface{} { return new(Data2) })
    }
    
    func SenderData(address string, buff *filebuffer.Buffer, newfn func() interface{}) {
        var conn net.Conn
        var err error
        var line string
        for {
            line, err = buff.Pop()
            if err != nil {
                log.Critical("Error Poping:", err.Error())
                continue
            }
            if len(line) == 0 {
                time.Sleep(1 * time.Second)
                continue
            }
            obj := newfn()
            if err := json.Unmarshal([]byte(line), obj); err != nil {
                log.Critical("Error Unmarshaling:", err.Error())
                continue
            }
            for {
                log.Info("Trying to connect with Server...")
                conn, err = net.Dial(PROTO, address)
                // If err try to connect again
                if err != nil {
                    log.Error("Error connecting:", err.Error())
                    time.Sleep(1 * time.Second)
                    continue
                }
                // If connected break the loop
                break
            }
            log.Debug("Sending ", obj, " to:", address)
    
            encoder := gob.NewEncoder(conn)
            err := encoder.Encode(obj)
            if err != nil {
                log.Critical("Error Encoding Gob:", err.Error())
            }
            // Timer between every sending, ie. Reading from buffer
            time.Sleep(300 * time.Millisecond)
            conn.Close()
        }
    }
    

    此答案中的代码每次通过循环分配一个新值,而问题中的代码分配一次对象。每次通过循环进行分配可以防止接收到的 JSON 对象之间的串扰。

    【讨论】:

    • 我怎样才能这样命名?我从来没有想过这样的事情。
    • 我对以通道为参数的函数也有同样的问题,我可以对这样的函数做同样的事情吗?
    猜你喜欢
    • 2011-09-23
    • 1970-01-01
    • 1970-01-01
    • 2023-03-27
    • 1970-01-01
    • 2018-10-01
    • 2012-11-16
    • 2014-09-11
    • 1970-01-01
    相关资源
    最近更新 更多