我需要为每种构建类型创建构建器(基础)和特定构建器。
e.g.
builder for html project
builder for node.js project
builder for python project
builder for java project
……
主要功能如下:
文件:Builder.go
界面
type Builder interface {
Build(string) error
}
文件:nodebuilder.go
//This is the struct ???? not sure what to put here...
type Node struct {
}
func (n Node) Build(path string) error {
//e.g. Run npm install which build's nodejs projects
command := exec.Command("npm", "install")
command.Dir = “../path2dir/“
Combined, err := command.CombinedOutput()
if err != nil {
log.Println(err)
}
log.Printf("%s", Combined)
}
...
//return new(error)
}
主要假设/过程:
mvn build
npm install
等)注意:除了
build
和 path
(应该专门处理)所有其他功能都相同喜欢
zip
copy
Where should I put the the
zip and copy
(in the structure) and for example how should I implement them and path them to the builder ?Should I structure the project differently according the assumptions?
最佳答案
Go 不是面向对象的语言。这意味着根据设计,您不必将类型的所有行为都封装在类型本身中。当您认为我们没有继承时,这很方便。
当你想在另一种类型上构建一个类型时,你可以使用组合:a struct
可以嵌入其他类型,并公开它们的方法。
假设您有一个 MyZipper
暴露 Zip(string)
的类型方法和 MyCopier
暴露了 Copy(string)
方法:
type Builder struct {
MyZipper
MyCopier
}
func (b Builder) Build(path string) error {
// some code
err := b.Zip(path)
if err != nil {
return err
}
err := b.Copy(path)
if err != nil {
return err
}
}
这是 Go 中的组合。更进一步,如果您只想从
myZipper
中调用它们,您甚至可以嵌入非公开类型(例如 myCopier
和 builder
)包裹。但是,为什么首先要嵌入它们呢?您可以为 Go 项目选择几种不同的有效设计。
解决方案 1:单个包暴露多个 Builder 类型
在这种情况下,您需要一个
builder
包,这将公开多个构建器。zip
和 copy
是在包中某处定义的两个函数,它们不需要是附加到类型的方法。package builder
func zip(zip, args string) error {
// zip implementation
}
func cp(copy, arguments string) error {
// copy implementation
}
type NodeBuilder struct{}
func (n NodeBuilder) Build(path string) error {
// node-specific code here
if err := zip(the, args); err != nil {
return err
}
if err := cp(the, args); err != nil {
return err
}
return nil
}
type PythonBuilder struct{}
func (n PythonBuilder) Build(path string) error {
// python-specific code here
if err := zip(the, args); err != nil {
return err
}
if err := cp(the, args); err != nil {
return err
}
return nil
}
方案二:单一封装,单一类型嵌入特定行为
根据特定行为的复杂性,您可能不想更改 Build 函数的整个行为,而只想注入(inject)特定行为:
package builder
import (
"github.com/me/myproj/copier"
"github.com/me/myproj/zipper"
)
type Builder struct {
specificBehaviour func(string) error
}
func (b Builder) Build(path string) error {
if err := specificBehaviour(path); err != nil {
return err
}
if err := zip(the, args); err != nil {
return err
}
if err := copy(the, args); err != nil {
return err
}
return nil
}
func nodeSpecificBehaviour(path string) error {
// node-specific code here
}
func pythonSpecificBehaviour(path string) error {
// python-specific code here
}
func NewNode() Builder {
return Builder{nodeSpecificBehaviour}
}
func NewPython() Builder {
return Builder{pythonSpecificBehaviour}
}
解决方案 3:每个特定构建器一个包
另一方面,根据您要在项目中使用的包粒度,您可能希望为每个构建器使用不同的包。在此前提下,您希望对共享功能进行足够的概括,以赋予其作为包的公民身份。例子:
package node
import (
"github.com/me/myproj/copier"
"github.com/me/myproj/zipper"
)
type Builder struct {
}
func (b Builder) Build(path string) error {
// node-specific code here
if err := zipper.Zip(the, args); err != nil {
return err
}
if err := copier.Copy(the, args); err != nil {
return err
}
return nil
}
解决方案4:函数!
如果您知道您的构建器将是纯函数式的,这意味着它们不需要任何内部状态,那么您可能希望您的构建器成为功能类型而不是接口(interface)。如果这是您想要的,您仍然可以从消费者方面将它们作为单一类型进行操作:
package builder
type Builder func(string) error
func NewNode() Builder {
return func(string) error {
// node-specific behaviour
if err := zip(the, args); err != nil {
return err
}
if err := copy(the, args); err != nil {
return err
}
return nil
}
}
func NewPython() Builder {
return func(string) error {
// python-specific behaviour
if err := zip(the, args); err != nil {
return err
}
if err := copy(the, args); err != nil {
return err
}
return nil
}
}
我不会针对您的特定情况使用函数,因为您需要为每个 BUilder 解决非常不同的问题,并且您肯定会在某个时候需要一些状态。
......如果你有一个无聊的下午,我会让你很高兴将其中的一些技巧结合在一起。
奖金!
error
关键字是接口(interface),不是类型!您可以 return nil
如果你没有错误。 Builder
builder
中的界面包:你不需要它。 Builder
接口(interface)将位于消费者包中。 关于go - 在 GO 中使用构建器的继承,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48264882/