代码之家  ›  专栏  ›  技术社区  ›  Flo

GO中的开放式设计和可扩展性

  •  0
  • Flo  · 技术社区  · 8 年前

    我试图在go中实现某种具有可扩展性的开放式设计范式,但我想知道gopher是如何做到这一点的。

    例如,我有一个车辆包。根据可用的实现,我想创建一个包含所有可能车辆的阵列。在本例中,如果只有bike可用,我需要一个数组[bike],如果我需要另一个car实现[bike,car]

    我真的不知道如何在围棋中做到这一点。我考虑在车辆包中使用接口,但我不知道如何根据可用的包创建阵列。这应该是开放式设计,这样如果有人决定写另一辆车,一辆卡车,即它会自动向上游工作。

    这是解释问题的一些示例代码: 如果没有必要将它们分为多个包,它们也可以在同一个包中(车辆)

    交通工具去

    package vehicle
    
    type vehicle interface {
        drive() string
    }
    

    自行车去

    package bike
    
    type bike struct {
        name string
    }
    
    func (b *bike) drive() string {
        return "drive bike drive"
    }
    
    func NewVehicle() bike {
        return &bike{
            name: "bike",
        }
    }
    

    汽车去

    package car
    
    type carstruct {
        name string
    }
    
    func (b *car) drive() string {
        return "drive cardrive"
    }
    
    func NewVehicle() car{
        return &car{
            name: "car",
        }
    }
    
    1 回复  |  直到 8 年前
        1
  •  0
  •   leaf bebop    8 年前

    我认为 image database/sql 以及它们如何与其他LIB合作,更具idomatic,但如果你真的需要实施这种设计,我想出了一些hack-y。

    诀窍是,golang可以在声明全局变量期间进行函数调用,而这发生在调用任何 init . 所以我们可以在这期间进行注册工作。

    //vehicle.go
    import (
        "fmt"
    )
    
    var _ = register("3",4)
    
    type constructor func() *Vehicle
    
    var reg = make(map[string]consturctor)
    
    func register(name string, cons) bool {
        _,ok:=reg[name]
        if ok {
            return false
        }
        reg[name] = cons
        return true
    }
    
    var chosen string
    
    func init() {
        //turn that map into a slice if you want
        //Chose one "implentation" from the slice/map if you wish
        for chosen = range reg {
            break // Take the first, it is dirty, I know.
        }
        if Chosen=="" {
            panic("No Implentation!")
        }
    }
    
    func NewVehicle() *Vehicle {
        return reg[chosen]() 
    }
    
    func main() {
        fmt.Println("Hello, playground")
    }
    
    //car.go
    
    var carsucc = register("car",constructor(NewCar))
    
    func init() {
        if !carsucc {
            panic("car: multiple implentation!")
        }
        //off course you can fail silently
    }
    
    func NewCar() Vehicle {
        return &Car{}
    }