英文:
Property change notification in go
问题
你可以在Go语言中通过使用观察者模式来向多个接收器发出“属性”更改的信号。观察者模式是一种设计模式,用于在对象之间建立一对多的依赖关系,当一个对象的状态发生变化时,它的所有依赖对象都会收到通知。
在Go语言中,你可以使用接口和回调函数来实现观察者模式。首先,你需要定义一个接口,该接口包含一个用于接收属性更改通知的方法。然后,你可以在需要接收属性更改通知的结构体中实现该接口,并将其注册为观察者。
以下是一个示例代码:
package main
import "fmt"
// 定义观察者接口
type Observer interface {
Update(value int)
}
// 定义可观察的属性结构体
type Property struct {
observers []Observer
value int
}
// 注册观察者
func (p *Property) Attach(observer Observer) {
p.observers = append(p.observers, observer)
}
// 取消注册观察者
func (p *Property) Detach(observer Observer) {
for i, o := range p.observers {
if o == observer {
p.observers = append(p.observers[:i], p.observers[i+1:]...)
break
}
}
}
// 更新属性值并通知观察者
func (p *Property) SetValue(value int) {
p.value = value
p.Notify()
}
// 通知观察者属性值的更改
func (p *Property) Notify() {
for _, observer := range p.observers {
observer.Update(p.value)
}
}
// 实现观察者接口的结构体
type ProgressBar struct{}
func (pb ProgressBar) Update(value int) {
fmt.Printf("Progress bar updated: %d%%\n", value)
}
type TextView struct{}
func (tv TextView) Update(value int) {
fmt.Printf("Text view updated: %d%%\n", value)
}
func main() {
// 创建可观察的属性
progress := Property{}
// 创建观察者
progressBar := ProgressBar{}
textView := TextView{}
// 注册观察者
progress.Attach(progressBar)
progress.Attach(textView)
// 更新属性值并通知观察者
progress.SetValue(50)
}
在上面的示例代码中,我们定义了一个Property
结构体作为可观察的属性,它包含一个observers
切片用于存储观察者,以及一个value
字段表示属性的值。我们还定义了一个Observer
接口,其中包含一个Update
方法用于接收属性更改通知。
在main
函数中,我们创建了一个progress
属性实例以及一个ProgressBar
和一个TextView
观察者实例。然后,我们通过调用Attach
方法将观察者注册到属性中。最后,我们通过调用SetValue
方法更新属性值,并自动通知所有观察者。
当属性值发生更改时,观察者的Update
方法将被调用,并传递新的属性值作为参数。在示例中,观察者只是简单地打印出属性值的更新信息,你可以根据实际需求进行相应的处理。
希望这可以帮助到你!
英文:
How can you signal 'property' changes to multiple receivers in go?
Similar to how you would define a property in Qt with a notify signal.
E.g. if you imagine having some value that needs to be shown in multiple ways, like a progress value that could be shown both as a progress bar and as textual %, where both would need to update when the underlying value changes.
答案1
得分: 5
一种方法是利用通道(channels)。
你的中央代码负责管理/更改需要监听的属性或变量,可以提供一个GetChan()
函数,该函数返回一个通道,用于广播修改(例如新值):
// 被监听的变量或属性:
var i int
// 所有监听器的切片
var listeners []chan int
func GetChan() chan int {
listener := make(chan int, 5)
listeners = append(listeners, listener)
return listener
}
每当你改变变量/属性时,你需要广播这个变化:
func Set(newi int) {
i = newi
for _, ch := range listeners {
ch <- i
}
}
监听器需要“监听”变化事件,可以通过对GetChan()
返回的通道进行for range
循环来实现:
func Background(name string, ch chan int, done chan int) {
for v := range ch {
fmt.Printf("[%s] 值发生变化:%d\n", name, v)
}
done <- 0
}
以下是主程序:
func main() {
l1 := GetChan()
l2 := GetChan()
done := make(chan int)
go Background("B1", l1, done)
go Background("B2", l2, done)
Set(3)
time.Sleep(time.Second) // 等待一段时间
Set(5)
// 关闭所有监听器:
for _, listener := range listeners {
close(listener)
}
// 等待2个后台线程完成:
<-done
<-done
}
它的输出结果是:
[B1] 值发生变化:3
[B2] 值发生变化:3
[B1] 值发生变化:5
[B2] 值发生变化:5
你可以在Go Playground上尝试完整的程序。
你还可以实现一个“代理人(broker)”,实现订阅者模型并允许广播消息。参考:https://stackoverflow.com/questions/36417199/how-to-broadcast-message-using-channel/49877632#49877632。
英文:
One way could to be to utilize channels.
Your central code which manages/changes the property or variable that needs to be listened may provide a GetChan()
function which returns a channel on which modifications (e.g. new values) will be broadcasted:
// The variable or property that is listened:
var i int
// Slice of all listeners
var listeners []chan int
func GetChan() chan int {
listener := make(chan int, 5)
listeners = append(listeners, listener)
return listener
}
Whenever you change the variable/property, you need to broadcast the change:
func Set(newi int) {
i = newi
for _, ch := range listeners {
ch <- i
}
}
And listeners need to "listen" for change events, which can be done by a for range
loop on the channel returned by GetChan()
:
func Background(name string, ch chan int, done chan int) {
for v := range ch {
fmt.Printf("[%s] value changed: %d\n", name, v)
}
done <- 0
}
Here is the main program:
func main() {
l1 := GetChan()
l2 := GetChan()
done := make(chan int)
go Background("B1", l1, done)
go Background("B2", l2, done)
Set(3)
time.Sleep(time.Second) // Wait a little
Set(5)
// Close all listeners:
for _, listener := range listeners {
close(listener)
}
// Wait 2 background threads to finish:
<-done
<-done
}
And its output:
[B1] value changed: 3
[B2] value changed: 3
[B1] value changed: 5
[B2] value changed: 5
You can try the complete program on the Go Playground.
You may also implement a "broker" which realizes a subscriber model and allows broadcasting messages. See https://stackoverflow.com/questions/36417199/how-to-broadcast-message-using-channel/49877632#49877632.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论