go - 在 GO 中使用构建器的继承

标签 go

我需要为每种构建类型创建构建器(基础)和特定构建器。

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)
}

主要假设/过程:
  • 要开始构建每个模块,我需要获取它的路径
  • 我需要将模块复制到临时文件夹
  • 我需要在其上运行构建(实现构建接口(interface),如 mvn build npm install 等)
  • 构建完成后,使用 dep
  • 压缩模块
  • 将其复制到新的目标文件夹

  • 注意:除了buildpath (应该专门处理)所有其他功能都相同
    喜欢 zip copy
    1. 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 ?

    2. 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 中调用它们,您甚至可以嵌入非公开类型(例如 myCopierbuilder )包裹。但是,为什么首先要嵌入它们呢?

    您可以为 Go 项目选择几种不同的有效设计。

    解决方案 1:单个包暴露多个 Builder 类型

    在这种情况下,您需要一个 builder包,这将公开多个构建器。
    zipcopy是在包中某处定义的两个函数,它们不需要是附加到类型的方法。
    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/

    相关文章:

    go - 丢弃字符串到 int 转换的错误值

    go - golang 上的公历包

    http - 如何在 Go 的测试中模拟 http 请求的 504 超时错误?

    go - 如何使用 "crypto/rand"包生成随机整数?

    去和多播(特别是 ospf)

    multithreading - golang线程数误导

    ajax - 由于 CORS,Nginx 反向代理后面的 Golang 应用程序不会接受 firefox 上的 ajax 请求

    regex - 在字符串中查找文件路径

    go - 使用配置文件连接到 Kubernetes 服务器时处理错误

    go - 如何列出特定Go软件包下的所有子软件包?