要点 https://gist.github.com/anonymous/68c3b072538ec48c2667f7db276e781b是我在尝试记录的现有代码库中遇到的重复 golang 代码模式的最小简化示例。从它的用法来看,它似乎类似于 mixin,但我自己或我的任何同事之前都没有在 golang 中真正见过这种模式。谁能告诉我这个模式合适的既定名称?
要点试图说明:
- 多个类型(A 和 B)使用的未修改行为实现代码(M 的函数)。
- 通过组合包含在主机类型(A 和 B)中。
- 通过 host.behaviour.method(...) 调用导出和访问的行为方法,例如a.Formatter.FormatText(...).
- 宿主方法受行为影响。
- 行为持有修改行为执行的状态(私有(private)或导出)。
- 通过传递行为字段,需要该行为的函数可以使用添加了特定行为的类型,例如b := NewB().Formatter.
- 可以将许多不同的行为组合成一个给定的类型(为简洁起见,实际上并未显示,但您可以想象将 M1、M2、M3 等包含在 A 或 B 中)。
它似乎并不严格满足 mixin 的大部分定义,因为它在编写时以超出 M 知识范围的方式操作宿主对象(可能修改宿主状态)并且不直接向宿主添加方法输入:
它似乎与我发现的一些自称为“golang mixins”的模式不一样:
最佳答案
长篇小说
- 这些不是混入。
- 是的,Go 有 mixins。
更长
您的示例只是带有公开结构字段的组合。虽然这类似于 mixin,但并不相同。你甚至给出了真正的 mixins 的例子(在 Go 中)。
我会给自己一个,并说明为什么它有用。
假设您想对人大喊大叫。然后你需要一个 Yeller
接口(interface)。此外,在这种情况下,我们需要一个 Yell
函数,它接受一个 Yeller
并使用它来喊叫。这是代码:
type Yeller interface {
Yell(message string)
}
func Yell(m Yeller, message string) {
m.Yell(message)
}
谁敢骂?好吧,人们大喊大叫,所以我们会创造一个。我们当然可以直接在人身上实现 Yeller
接口(interface):
type Person struct {}
func (p *Person) Yell(message string) { /* yell */ }
// Let a person yell.
person := &Person{}
Yell(person, "No")
现在 Person
被困在一个实现中,也许我们不希望这样。所以,你已经给出了解决方案:
type Person struct {
Yeller Yeller
}
person := &Person{ /* Add some yeller to the mix here */ }
但是现在,如果我们想让person
大喊大叫,我们不能直接使用我们的函数,因为Person
没有实现Yeller
。
// Won't work
Yell(person, "Loud")
相反,我们必须明确告诉 Yell
使用 Person
的 Yeller
。
// Will work
Yell(person.Yeller, "No")
还有一种可能。我们可以让 Person
通过将调用传递给 Person
的 Yeller
来实现 Yeller
。
func (p *Person) Yell(message string) {
p.Yeller.Yell(message)
}
// Will work again!
Yell(person, "Yes")
但这迫使我们编写大量样板代码,我们混合的方法数乘以“实现”的数量。
我们可以使用 Go 的 mixin 工具做得更好。
type Person struct {
Yeller
}
p := &Person { /* Add some Yeller to the mix here */ }
Yell(p, "Hooray")
现在 Person
是一个 Yeller
,将 Yell
调用传递给包装的 Yeller
。无需样板文件。
为什么有用?想象一下,您还想要 Whisper
,创建一个 Whisperer
接口(interface),并且您想要一个 RoboticVoice
也可以 Whisper
和大喊
。
您可以编写类似的代码,Person
和 RoboticVoice
都可以采用 Yeller
和 Whisperer< 的不同实现来组合
s.
最后但同样重要的是,您仍然可以通过让结构自己实现方法来覆盖行为。
这里是完整的示例代码和 Golang Playground 的链接:
package main
import (
"fmt"
)
func main() {
Yell(&Person{ Yeller: yeller("%s!!!\n") }, "Nooooo")
Yell(&RoboticVoice{Yeller: twiceYeller("*** %s ***")}, "Oh no")
Whisper(&Person{ Whisperer: whisperer("Sssssh! %s!\n")}, "...")
Whisper(&RoboticVoice{ Whisperer: whisperer("Sssssh! %s!\n")}, "...")
}
type Yeller interface {
Yell(message string)
}
func Yell(y Yeller, message string) {
y.Yell(message)
}
type Whisperer interface {
Whisper(message string)
}
func Whisper(w Whisperer, message string) {
w.Whisper(message)
}
type Person struct {
Yeller
Whisperer
}
type RoboticVoice struct {
Yeller
Whisperer
}
func (voice *RoboticVoice) Yell(message string) {
fmt.Printf("BEEP! ")
voice.Yeller.Yell(message)
fmt.Printf(" BOP!\n")
}
func (voice *RoboticVoice) Whisper(message string) {
fmt.Printf("Error! Cannot whisper! %s\n", message)
}
type yeller string
func (y yeller) Yell(message string) {
fmt.Printf(string(y), message)
}
type twiceYeller string
func (twice twiceYeller) Yell(message string) {
fmt.Printf(string(twice+twice), message, message)
}
type whisperer string
func (w whisperer) Whisper(message string) {
fmt.Printf(string(w), message)
}
关于go - golang代码是否有一个既定的模式名称,看起来类似于mixin,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40091142/