GO 中的开放式设计和可扩展性
Open Design and expandability in GO
我尝试在 go 中实现某种具有可扩展性的开放式设计范例,但想知道这样做的 gopher 方法是什么。
例如我有一个车辆包。根据可用的实现方式,我想创建一个包含所有可能车辆的数组。在这个例子中,如果只有自行车可用,我想要一个数组 [bike] 如果还有另一个汽车实现,我想要 [bike,car]
我真的不知道如何在 go 中执行此操作。我想到了车辆包中的接口,但我真的不知道如何根据可用的包创建数组。这应该是开放式设计,这样如果有人决定编写另一辆车,一辆卡车,即它会自动在上游工作。
所以这是解释问题的一些示例代码:
如果没有必要,它们被分成包,它们也可以在同一个包中(车辆)
vehicle.go
package vehicle
type vehicle interface {
drive() string
}
bike.go
package bike
type bike struct {
name string
}
func (b *bike) drive() string {
return "drive bike drive"
}
func NewVehicle() bike {
return &bike{
name: "bike",
}
}
car.go
package car
type carstruct {
name string
}
func (b *car) drive() string {
return "drive cardrive"
}
func NewVehicle() car{
return &car{
name: "car",
}
}
我认为 image
和 database/sql
的设计以及它们与其他库的合作方式更加惯用,但如果您真的需要实施这种设计,我已经提出有一些骇人听闻的东西。
诀窍是,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{}
}
我尝试在 go 中实现某种具有可扩展性的开放式设计范例,但想知道这样做的 gopher 方法是什么。
例如我有一个车辆包。根据可用的实现方式,我想创建一个包含所有可能车辆的数组。在这个例子中,如果只有自行车可用,我想要一个数组 [bike] 如果还有另一个汽车实现,我想要 [bike,car]
我真的不知道如何在 go 中执行此操作。我想到了车辆包中的接口,但我真的不知道如何根据可用的包创建数组。这应该是开放式设计,这样如果有人决定编写另一辆车,一辆卡车,即它会自动在上游工作。
所以这是解释问题的一些示例代码: 如果没有必要,它们被分成包,它们也可以在同一个包中(车辆)
vehicle.go
package vehicle
type vehicle interface {
drive() string
}
bike.go
package bike
type bike struct {
name string
}
func (b *bike) drive() string {
return "drive bike drive"
}
func NewVehicle() bike {
return &bike{
name: "bike",
}
}
car.go
package car
type carstruct {
name string
}
func (b *car) drive() string {
return "drive cardrive"
}
func NewVehicle() car{
return &car{
name: "car",
}
}
我认为 image
和 database/sql
的设计以及它们与其他库的合作方式更加惯用,但如果您真的需要实施这种设计,我已经提出有一些骇人听闻的东西。
诀窍是,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{}
}