Go言語でシンプルなObserverパターンのコードを書いてみました。
go
1package main 2 3import "fmt" 4 5// 具象クラス Subject 6// ======================= 7 8type Subject struct { 9 name string 10 observers []Observer 11} 12 13func newSubject(name string) *Subject { 14 return &Subject{name: name, observers: []Observer{}} 15} 16 17func (s *Subject) addObserver(o Observer) { 18 s.observers = append(s.observers, o) 19} 20 21func (s *Subject) notifyObservers() { 22 for _, observer := range s.observers { 23 observer.notify() 24 } 25} 26 27// 具象クラス Observer 28// ======================= 29 30type Notify interface { 31 notify() 32} 33 34type Observer struct { 35 name string 36} 37 38func newObserver(name string) *Observer { 39 return &Observer{name: name} 40} 41 42func (o *Observer) notify() { 43 fmt.Printf("hello! i am %v\n", o.name) 44} 45 46// main 47// ======================= 48 49func main() { 50 s := newSubject("sms") 51 mom := newObserver("mom") 52 gf := newObserver("girlFriend") 53 54 s.addObserver(*mom) 55 s.addObserver(*gf) 56 57 s.notifyObservers() 58} 59
上のコードは一応動くのですが、一つinterfaceの実装の方法がわからないことによる問題が生じています。(上のコードでは宣言したNotifyはどこにも使われていません)
構造体SubjectのもつnotifyObservers()メソッドの中で、プロパティobserversが持つnotify()メソッドを実行している部分があります。
Goではない、例えばTypeScript等の場合は、Observerクラスを作るときに、「nameプロパティ」と「notifyメソッド」をもつinterfaceをimplementsすることで、Observerクラスのインスタンスはこれら2つを持っていることがわかります。
typescript
1interface Observer { 2 name: string; 3 notify: () => string 4}
ですが、Goの場合、struct内に定義できるのはプロパティのみなので、これがnotify()メソッドを持っていることは保証できません。
イメージ的には、上のTypeScriptと同じように以下のように書きたいのですが、文法上それはできません。
Go
1type Observer struct { 2 name string 3 notify() 4}
このように、あるクラスに対してこのメソッドを絶対持たせたいことを宣言するために、Goではどのように書くのでしょうか。
どなたかご存知の方がいらっしゃればご教示願えませんでしょうか。
よろしくおねがいします。
【追記】
少しひらめきました。
以下のように書くというのはどうでしょうか。
Notifyインターフェースのみを受け付けるnObserver関数を別に用意し、それをfor文の中で実行しています。
go
1// 略 2 3func (s Subject) notifyObservers() { 4 for _, observer := range s.observers { 5 nObserver(observer) 6 } 7} 8 9func nObserver(n Notify) { 10 n.notify() 11} 12 13// 具象クラス Observer 14// ======================= 15 16type Notify interface { 17 notify() 18} 19 20// 略
【追記の追記】
nobonoboさんのヒントを元に再度修正してみました。
(最初の質問時のコードと整合性を取るために付け足しコードになっており、一部命名がおかしいと感じながらもそのままにしている部分があります)
「Observerはnotify()メソッドを持ってさえいればいい」。
なので、Subject構造体のプロパティobserversの型は、Observer構造体ではなく、Notifyインターフェースであれば良いということでしょうか
go
1type Subject struct { 2 name string 3 observers []Notify // ココ 4} 5 6func newSubject(name string) *Subject { 7 return &Subject{name: name, observers: []Notify{}} // ココ 8} 9 10func (s *Subject) addObserver(o Notify) { // ココ 11 s.observers = append(s.observers, o) 12} 13 14func (s Subject) notifyObservers() { 15 for _, observer := range s.observers { 16 observer.notify() 17 } 18} 19 20// func nObserver(n Notify) { 21// n.notify() 22// } 23 24// 具象クラス Observer 25// ======================= 26 27type Notify interface { 28 notify() 29}
回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
退会済みユーザー
2018/10/28 04:30
退会済みユーザー
2018/10/28 04:50
2018/10/28 05:02
退会済みユーザー
2018/10/28 05:11
2018/10/28 07:12
退会済みユーザー
2018/10/28 07:23