質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
Go

Go(golang)は、Googleで開発されたオープンソースのプログラミング言語です。

デザインパターン

デザインパターンは、ソフトウェアのデザインでよく起きる問題に対して、解決策をノウハウとして蓄積し再利用出来るようにした設計パターンを指します。

Q&A

解決済

1回答

3196閲覧

Goで抽象クラスありのObserverパターンを実装したい

退会済みユーザー

退会済みユーザー

総合スコア0

Go

Go(golang)は、Googleで開発されたオープンソースのプログラミング言語です。

デザインパターン

デザインパターンは、ソフトウェアのデザインでよく起きる問題に対して、解決策をノウハウとして蓄積し再利用出来るようにした設計パターンを指します。

0グッド

0クリップ

投稿2018/10/18 12:55

Observerパターンの勉強をしているのですが、言語的なこだわりはあまりないので練習がてら、最近始めたGoで書いてみようと思いました。

PHPで解説されたこのページのコードをGoに書き直そうとしているのですが、うまくいきません。
上記のコードの最初の「実装コード」の部分です。
簡単のために、idやtimeなど一部省略したり、具象クラスもGirlFriendのみにしています。

Go

1package main 2 3import "fmt" 4 5// ======================= 6// 抽象クラス Subject 7// ======================= 8 9type Subject struct { 10 observers []Observer 11} 12 13func NewSubject() *Subject { 14 return &Subject{observers: []Observer{}} 15} 16 17func (self *Subject) registerObser(observer Observer) { 18 self.observers = append(self.observers, observer) 19} 20 21// func removeObserver 22 23// func (self *Subject) notify() {} 24 25// ======================= 26// 具象クラス SMS extends Subject 27// ======================= 28 29type SMS struct { 30 *Subject 31} 32 33func NewSMS() *SMS { 34 return &SMS{Subject: NewSubject()} 35} 36 37func (self *SMS) notifyObservers() { 38 for _, observer := range self.observers { 39 observer.notify() 40 } 41} 42 43func (self *SMS) iAmHome() { 44 self.notifyObservers() 45} 46 47// ======================= 48// 抽象クラス Observer 49// ======================= 50 51type IObserver interface { 52 notify() 53} 54 55type Observer struct { 56 id int 57 subject SMS 58 IObserver 59} 60 61// constructor 62func NewObserver(id int, subject SMS) *Observer { 63 // subject.registerObser() 64 return &Observer{id: id, subject: subject} 65} 66 67// ======================= 68// 具象クラス GirlFriend,Mum extends Observer 69// ======================= 70 71type GirlFriend struct { 72 *Observer 73} 74 75func NewGirlFriend(id int, subject SMS) *GirlFriend { 76 return &GirlFriend{Observer: NewObserver(id, subject)} 77} 78 79func (self *GirlFriend) notify(time string) { 80 fmt.Printf("今帰ったよ %v", time) 81} 82 83// ======================= 84// main 85// ======================= 86 87func main() { 88 89 sms := NewSMS() 90 NewGirlFriend(2, *sms) 91 92 sms.iAmHome() 93} 94

Goはオブジェクト指向の言語ではない(?)ので、上のコードはGoらしくないコードになっているかと思います。

私が知りたいのは、上のコードを動かす書き方と、上記のサイトの内容を同じ程度の柔軟性をもったGoの書き方です。

オブジェクト指向もObserverパターンもGo言語自体も詳しく知らない状態です。

ツッコミどころは沢山あるかと思いますが、どなたかご存知の方がいらっしゃればご教示願えませんでしょうか。
よろしくおねがいします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

wikipedia:Observer パターンを参考にGoで実装した例を以下に示します。

https://play.golang.org/p/lwNkVd2nzyg

go

1package main 2 3import ( 4 "fmt" 5 "sync" 6) 7 8type Param string 9 10type Observer interface { 11 Notify(p Param) 12} 13 14type Subject struct { 15 mu sync.RWMutex 16 observers []Observer 17} 18 19func (nb *Subject) AddObserver(o Observer) { 20 nb.mu.Lock() 21 defer nb.mu.Unlock() 22 nb.observers = append(nb.observers, o) 23} 24 25func (nb *Subject) DeleteObserver(o Observer) { 26 nb.mu.Lock() 27 defer nb.mu.Unlock() 28 obs := nb.observers[0:0] 29 for _, v := range nb.observers { 30 if v != o { 31 obs = append(obs, v) 32 } 33 } 34 nb.observers = obs 35} 36 37func (nb *Subject) Notify(p Param) { 38 nb.mu.RLock() 39 defer nb.mu.RUnlock() 40 for _, v := range nb.observers { 41 v.Notify(p) 42 } 43} 44 45type Something struct { 46 Subject 47} 48 49type Observer1 struct{} 50 51func (o1 *Observer1) Notify(p Param) { 52 fmt.Println("obs1:", p) 53} 54 55type Observer2 struct{} 56 57func (o1 *Observer2) Notify(p Param) { 58 fmt.Println("obs2:", p) 59} 60 61func main() { 62 s := &Something{} 63 ob1 := &Observer1{} 64 ob2 := &Observer2{} 65 s.AddObserver(ob1) 66 s.AddObserver(ob2) 67 s.Notify("hello!") 68 s.DeleteObserver(ob1) 69 s.Notify("World!") 70}

Observerになれるのは「Notify(p Param)」というメソッドを持つというのが条件です。
Subjectにsync.RWMutexがあるのは複数のgoroutineから操作されても大丈夫なようにするためです。
(蛇足かもしれませんが、この例ではSubjectも「Notify(p Param)」というメソッドを持っているのでObserverになれます。例えば通知にツリー構造を構築することもできます。)

投稿2018/10/22 07:54

nobonobo

総合スコア3367

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問