Golang Go语言中程序结构的探讨
一个项目就是几个模块的组合,假设有 3 个模块,目前我看到以下几种架构:
type InterfaceA interface {
MethodA1()
MethodA2()
}
type structA struct {
a int
}
func (a *structA)MedhtodA1() {}
func (a *structA)MedhtodA2() {}
func (a *structA)run(context) {
for {
// MethodA1() 和 MethodA2() 的一些调用
}
}
func NewStructA() structA {
a := structA{}
go a.run()
return a
}
// 类似的还有 InterfaceB/structB ,特点都是在 New 方法里面开了一个 goroutine ,运行 run 方法。
type InterfaceC interface {
MethodC1()
MethodC2()
MethodC3()
}
// 这里 c 的运行需要 a
type structC struct {
a struct
c string
}
func (c *structC)MedhtodC1() {}
func (c *structC)MedhtodC2() {}
func (c *structC)MedhtodC3() {}
func (a *structA)run(context) {
for {
// MethodC1()、MethodC2()、MethodC3()及 MethodA()的一些调用
}
}
func NewStructC() InterfaceC {
a := structA{}
c := structC{ a }
go c.run()
return c
}
type manager struct {
ib InterfaceB
ic InterfaceC
}
func NewManager() *manager{
ia := NewStructA()
ib := NewStructB()
ic := NewStructC(ia)
return &manager{
ib
ic
}
}
func (m *manager)run(ch) {
for {
select {
case <- ch:
return
}
}
}
func main() {
m := NewManager()
m.run()
}
这种架构的话,很清晰的表明了程序模块,比如直接从项目的目录结构就可以看到这个程序的几个模块(一个模块对应一个目录),每个模块的接口功能表达也很清晰。但是他的问题是,在阅读代码的时候,隐藏了程序里面的几个模块的执行和交互逻辑。比如我从 main 看到 manager 的时候,再看到 manager.run 方法就结束了,完全不知道程序内部的模块是怎么运行。
// 另外一种架构
type Module interface {
Run()
}
type StructA struct {
}
func (a *StructA) Run() {
a.methodA1()
a.methodA2()
}
type StructB struct {
}
func (a *StructB) Run() {
b.methodB1()
b.methodB2()
}
type StructC struct {
a StructA
}
func (a *StructC) Run() {
a.Run()
c.MethodC1()
c.MethodC2()
}
type manager struct {
b StructB
c StructC
}
func NewManager() *manager{
a := NewStructA()
b := NewStructB()
c := NewStructC(a)
return &manager{
b, c
}
}
func (m *manager)run(ch) {
go m.b.Run()
go m.c.Run()
for {
select {
case <- ch:
return
}
}
}
func main() {
m := NewManager()
m.run()
}
这样的话,阅读代码的时候,可以快速的知道程序的执行逻辑。但是吧,每个模块对外只有一个 Run 方法,模块本身的含义又没了。
这里,估计有人会提出下面的方案。
type Stage interface {
Run()
}
type InterfaceA interface {
Stage
MethodA1()
MethodA2()
}
type InterfaceB interface {
Stage
MethodB1()
MethodB2()
}
type InterfaceC interface {
Stage
MethodC1()
MethodC2()
MethodC3()
}
这个也是可行的,但是吧,看着别扭,因为这个 Run() 其实跟接口自身的含义没啥关系。
想问问大家,怎么设计程序的模块架构的。
Golang Go语言中程序结构的探讨
更多关于Golang Go语言中程序结构的探讨的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
不明白第一个问题,你的外层 run 起来后监听信号不就结束了吗 看代码到服务里去看
更多关于Golang Go语言中程序结构的探讨的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
run 是小写,外层调用不了
OP 的意思是,struct 的属性类型指定 interface 还是 struct 的问题?
如果我理解的没错的话,我的习惯是:
1. 属性类型用 interface
2. NewXXX 方法接受参数类型用 interface ,返回值用 struct
3. 看 interface 的实现用 IDE 的 go to implementation 功能,具体哪走的一个实现 debug 打断点看
interface 主要用在:
1 、可替换实现的地方
2 、会产生包依赖冲突的地方
其他情况下,不建议使用 interface
模式 1 ,定义了一堆 interface ,模块执行逻辑在 New 里面,间接在 run 里面。
模式 2 ,定义了一个通用的 Module 接口,模块实现 Module 接口,模块执行逻辑在 Run ,由 Manager 在 run 里面调用。
模式 3 ,定义了一个通用接口 Stage ,以及定义了一堆 interface ,模块实现 Stage 接口以及自身的接口,模块执行逻辑在 Run ,由 Manager 在 run 里面调用。
所以你这 3 种模式,无非就是抽取了一堆接口,有点 Java 了,代码的可读性没有任何区别。
首先,模式 1 的将模块执行触发丢在 New 里面,通常是不建议的,因为多模块系统是由模块组装得到的,最后再走启动的流程,模块提前执行是不合适的。
其次,除非真有必要,Go 是很少上来就抽取一堆 interface ,建议先写下原型,根据实际需要再抽取接口。
在Golang(通常简称为Go)中,程序结构是构建可靠和高效应用程序的基石。Go语言以其简洁明了的语法和强大的标准库著称,其程序结构同样体现了这些特点。
Go程序的基本结构由包(package)、函数(function)、变量(variable)和类型(type)等构成。每个Go源文件都以package
声明开始,这定义了文件所属的命名空间。main
包是特殊的,因为包含main
函数的包是可执行的。
函数是Go中执行代码的基本单元。每个函数都有明确的输入(参数)和输出(返回值)。Go支持多种类型的函数,包括匿名函数(闭包)和高阶函数,这使得代码更加灵活和模块化。
变量用于存储数据,Go语言提供了简洁的变量声明和初始化方式,包括短变量声明(使用:=
),这在函数内部特别有用。
类型是Go语言的核心特性之一,它提供了强大的类型系统和接口机制,使得代码更加健壮和易于维护。通过定义类型,我们可以确保函数接收和返回正确的数据,同时利用接口实现多态性。
此外,Go语言还提供了并发编程的支持,通过goroutine和channel,可以轻松地编写并发程序,而无需担心复杂的线程管理。
总之,Go语言的程序结构简洁而强大,通过合理使用包、函数、变量和类型等构造,可以编写出高效、可靠和易于维护的应用程序。