From 1c13d9c08e1551b5006c7f3774fb244edd84b9c3 Mon Sep 17 00:00:00 2001 From: sioncojp Date: Fri, 12 Nov 2021 13:00:20 +0900 Subject: [PATCH] update --- README.md | 26 ++++++++++ abstract_factory/README.md | 9 +++- adapter/README.md | 8 +-- adapter/adapter.go | 23 ++++----- adapter/adapter_test.go | 6 +-- adapter/client.go | 10 ++++ adapter/computer.go | 5 ++ adapter/mac.go | 10 ++++ adapter/windows.go | 9 ++++ adapter/windowsAdapter.go | 12 +++++ factory_method/README.md | 9 +++- prototype/README.md | 12 +++-- prototype/file.go | 15 ++++++ prototype/folder.go | 26 ++++++++++ prototype/inode.go | 6 +++ prototype/prototype.go | 59 ++++++++--------------- prototype/prototype_test.go | 12 +---- template_method/1/template_method.go | 33 ------------- template_method/1/template_method_test.go | 8 --- template_method/2/template_method.go | 32 ------------ template_method/2/template_method_test.go | 8 --- template_method/README.md | 11 +++-- template_method/email.go | 30 ++++++++++++ template_method/otp.go | 40 +++++++++++++++ template_method/sms.go | 30 ++++++++++++ template_method/template_method.go | 32 ++++++++++++ template_method/template_method_test.go | 7 +++ 27 files changed, 323 insertions(+), 165 deletions(-) create mode 100644 adapter/client.go create mode 100644 adapter/computer.go create mode 100644 adapter/mac.go create mode 100644 adapter/windows.go create mode 100644 adapter/windowsAdapter.go create mode 100644 prototype/file.go create mode 100644 prototype/folder.go create mode 100644 prototype/inode.go delete mode 100644 template_method/1/template_method.go delete mode 100644 template_method/1/template_method_test.go delete mode 100644 template_method/2/template_method.go delete mode 100644 template_method/2/template_method_test.go create mode 100644 template_method/email.go create mode 100644 template_method/otp.go create mode 100644 template_method/sms.go create mode 100644 template_method/template_method.go create mode 100644 template_method/template_method_test.go diff --git a/README.md b/README.md index 56eccdd..b08d9ca 100644 --- a/README.md +++ b/README.md @@ -43,3 +43,29 @@ - [observer](./observer) - [strategy](./strategy) - [visitor](./visitor) + +## 実装例 +|pattern|example| +|:---|:---| +|abstract_factory|| +|builder|| +|factory_method|| +|prototype|| +|singleton|| +|adapter|| +|bridge|| +|composite|| +|decorator|| +|facade|| +|flyweight|| +|proxy|| +|chain_of_repository|| +|iterator|| +|Memento|| +|state|| +|template_method|| +|command|| +|mediator|| +|observer|| +|strategy|| +|visitor|| diff --git a/abstract_factory/README.md b/abstract_factory/README.md index f3c5a0b..8765579 100644 --- a/abstract_factory/README.md +++ b/abstract_factory/README.md @@ -28,7 +28,12 @@ factory: 生成しなければならないオブジェクトを事前に知ることができない場合 abstractFactory: オブジェクトを選ぶ場合 -### 例題 +### 例題1 - ドアを取り付ける - 木製のドアと木製ドア取り付け職人 -- 鉄製のドアと鉄製ドア取り付け職人 \ No newline at end of file +- 鉄製のドアと鉄製ドア取り付け職人 + + +### 例題2 +- スポーツキット +- 靴とシャツを購入する必要がある diff --git a/adapter/README.md b/adapter/README.md index 46745da..9957005 100644 --- a/adapter/README.md +++ b/adapter/README.md @@ -27,7 +27,7 @@ Go は interface があり、struct の埋め込みがあるので adapter はそれで事足りる ### 例題 - -* 太郎くんはクラスを楽しくさせる力がある -* 太郎くんを学級委員にさせるが、太郎くんは能力がないと言う -* 成長した太郎くんは能力を身につけることができた +- オブジェクト(Lightningポート) +- 同じ機能を異なるインターフェイス(USBポート)で提供するadaptee(Windowsラップトップ)と呼ばれる別のオブジェクト +- クライアントが期待するのと同じインターフェース(Lightningポート)に準拠 +- アダプターはLightningコネクターを受け入れ、その信号をUSB形式に変換して、WindowsラップトップのUSBポートに渡す diff --git a/adapter/adapter.go b/adapter/adapter.go index 6a008b0..db2b770 100644 --- a/adapter/adapter.go +++ b/adapter/adapter.go @@ -1,20 +1,15 @@ package adapter -type ChairPerson interface { - OrganizeClass() -} - -type TaroV2 struct { - Taro -} +func main() { + client := &client{} + mac := &mac{} -type Taro struct{} + client.insertLightningConnectorIntoComputer(mac) -func (s *TaroV2) OrganizationClass() { - println("クラスの面倒みるよ") - s.Taro.EnjoyWithClassmate() -} + windowsMachine := &windows{} + windowsMachineAdapter := &windowsAdapter{ + windowMachine: windowsMachine, + } -func (s *Taro) EnjoyWithClassmate() { - println("わいわい") + client.insertLightningConnectorIntoComputer(windowsMachineAdapter) } diff --git a/adapter/adapter_test.go b/adapter/adapter_test.go index b37c499..dd6cd05 100644 --- a/adapter/adapter_test.go +++ b/adapter/adapter_test.go @@ -3,9 +3,5 @@ package adapter import "testing" func TestAdapter(t *testing.T) { - t1 := &Taro{} - t1.EnjoyWithClassmate() - - t2 := &TaroV2{*t1} - t2.OrganizationClass() + main() } diff --git a/adapter/client.go b/adapter/client.go new file mode 100644 index 0000000..f7b1b98 --- /dev/null +++ b/adapter/client.go @@ -0,0 +1,10 @@ +package adapter + +import "fmt" + +type client struct{} + +func (c *client) insertLightningConnectorIntoComputer(com computer) { + fmt.Println("Client inserts Lightning connector into computer.") + com.insertIntoLightningPort() +} diff --git a/adapter/computer.go b/adapter/computer.go new file mode 100644 index 0000000..bb73fef --- /dev/null +++ b/adapter/computer.go @@ -0,0 +1,5 @@ +package adapter + +type computer interface { + insertIntoLightningPort() +} diff --git a/adapter/mac.go b/adapter/mac.go new file mode 100644 index 0000000..c2b7436 --- /dev/null +++ b/adapter/mac.go @@ -0,0 +1,10 @@ +package adapter + +import "fmt" + +type mac struct { +} + +func (m *mac) insertIntoLightningPort() { + fmt.Println("Lightning connector is plugged into mac machine.") +} diff --git a/adapter/windows.go b/adapter/windows.go new file mode 100644 index 0000000..dfdefee --- /dev/null +++ b/adapter/windows.go @@ -0,0 +1,9 @@ +package adapter + +import "fmt" + +type windows struct{} + +func (w *windows) insertIntoUSBPort() { + fmt.Println("USB connector is plugged into windows machine.") +} diff --git a/adapter/windowsAdapter.go b/adapter/windowsAdapter.go new file mode 100644 index 0000000..30ba7d8 --- /dev/null +++ b/adapter/windowsAdapter.go @@ -0,0 +1,12 @@ +package adapter + +import "fmt" + +type windowsAdapter struct { + windowMachine *windows +} + +func (w *windowsAdapter) insertIntoLightningPort() { + fmt.Println("Adapter converts Lightning signal to USB.") + w.windowMachine.insertIntoUSBPort() +} diff --git a/factory_method/README.md b/factory_method/README.md index 62bf26c..6f0c4e1 100644 --- a/factory_method/README.md +++ b/factory_method/README.md @@ -24,8 +24,15 @@ - DIContainer = Factoryの集合体 - factoryはconrainerパッケージを用意するなり、配列で管理するなりしたほうが、一箇所に集約されて相互importの心配をしなくてよい -### 例題 +### 例題1 - TemplateMethodを応用して、 - 太郎くんはウィングガンダムが作りたいと言った - 次郎くんはゴッドガンダムが作りたいと言った - この際、どのガンダム作るかは彼らに任せよう! + +### 例題2 +- 前提として、クラスや継承などのOOP機能がないため、Goで従来のファクトリメソッドパターンを実装することは不可能 + - パターンの基本バージョンであるSimpleFactoryは引き続き実装できる +- さまざまな種類の武器を作成 +- iGun銃が持つべきすべてのメソッドを定義するインターフェースを作成 +- ak47, musket diff --git a/prototype/README.md b/prototype/README.md index d13dea3..921b598 100644 --- a/prototype/README.md +++ b/prototype/README.md @@ -9,8 +9,10 @@ * オブジェクトのコピーを生成することが複雑だったりする ### 例題 -* あなたは雪の結晶を100枚飾ります - * 雪の結晶の形を紙にきれいに描く - * 書いた線にあわせて紙を切り抜く -* 実際にきれいに雪の結晶を描くには時間がかかり、さらに何枚も用意するとなるととんでもない -* 最初に作成したものと同じものを作ろう +- OSファイルシステム +- フォルダにはファイルとフォルダが含まれ、ファイルやフォルダが含まれる +- 各ファイルとフォルダーは、inodeインターフェイスで表すことができる +- inodeインターフェースにもclone機能がある +- fileとfolder構造体はどちらもタイプ +- printとclone関数のinode typeを実装 +- \ No newline at end of file diff --git a/prototype/file.go b/prototype/file.go new file mode 100644 index 0000000..a20e29f --- /dev/null +++ b/prototype/file.go @@ -0,0 +1,15 @@ +package prototype + +import "fmt" + +type file struct { + name string +} + +func (f *file) print(indentation string) { + fmt.Println(indentation + f.name) +} + +func (f *file) clone() inode { + return &file{name: f.name + "_clone"} +} diff --git a/prototype/folder.go b/prototype/folder.go new file mode 100644 index 0000000..6869bcb --- /dev/null +++ b/prototype/folder.go @@ -0,0 +1,26 @@ +package prototype + +import "fmt" + +type folder struct { + children []inode + name string +} + +func (f *folder) print(indentation string) { + fmt.Println(indentation + f.name) + for _, i := range f.children { + i.print(indentation + indentation) + } +} + +func (f *folder) clone() inode { + cloneFolder := &folder{name: f.name + "_clone"} + var tempChildren []inode + for _, i := range f.children { + copy := i.clone() + tempChildren = append(tempChildren, copy) + } + cloneFolder.children = tempChildren + return cloneFolder +} diff --git a/prototype/inode.go b/prototype/inode.go new file mode 100644 index 0000000..81964d6 --- /dev/null +++ b/prototype/inode.go @@ -0,0 +1,6 @@ +package prototype + +type inode interface { + print(string) + clone() inode +} diff --git a/prototype/prototype.go b/prototype/prototype.go index dd4a7d4..d3d599e 100644 --- a/prototype/prototype.go +++ b/prototype/prototype.go @@ -2,43 +2,24 @@ package prototype import "fmt" -type cloneabler interface { - Get() string - clone() cloneabler -} - -type Person struct { - cloneable cloneabler -} - -type Pepper struct { - Figure string -} - -func Draw(s string) *Pepper { - fmt.Printf("%sを書くよ\n", s) - return &Pepper{Figure: s} -} - -func Cut(s string) *Pepper { - pepper := Draw(s) - fmt.Printf("%sの形に切るお\n", pepper.Figure) - return pepper -} - -func (s *Person) Register(c cloneabler) { - s.cloneable = c -} - -func (s *Person) CreateClone() cloneabler { - return s.cloneable.clone() -} - -func (s *Pepper) Get() string { - return s.Figure -} - -// スライスならdeep copyをする必要がある -func (s *Pepper) clone() cloneabler { - return &Pepper{s.Figure} +func main() { + file1 := &file{name: "File1"} + file2 := &file{name: "File2"} + file3 := &file{name: "File3"} + + folder1 := &folder{ + children: []inode{file1}, + name: "Folder1", + } + + folder2 := &folder{ + children: []inode{folder1, file2, file3}, + name: "Folder2", + } + fmt.Println("\nPrinting hierarchy for Folder2") + folder2.print(" ") + + cloneFolder := folder2.clone() + fmt.Println("\nPrinting hierarchy for clone Folder") + cloneFolder.print(" ") } diff --git a/prototype/prototype_test.go b/prototype/prototype_test.go index 3c11424..b9cbaa1 100644 --- a/prototype/prototype_test.go +++ b/prototype/prototype_test.go @@ -3,15 +3,5 @@ package prototype import "testing" func TestPrototype(t *testing.T) { - figure := "雪の結晶" - pepper := Cut(figure) - - you := &Person{} - you.Register(pepper) - - cloned := you.CreateClone() - - if cloned.Get() != pepper.Get() { - t.Errorf("failed") - } + main() } diff --git a/template_method/1/template_method.go b/template_method/1/template_method.go deleted file mode 100644 index 2d9450c..0000000 --- a/template_method/1/template_method.go +++ /dev/null @@ -1,33 +0,0 @@ -package template_method - -// 小文字にしてプライベートにする -type kit interface { - cut() - build() - paint() -} - -type Gundam struct { -} - -func (s *Gundam) Create(kit kit) { - kit.cut() - kit.build() - kit.paint() -} - -type Taro struct { - *Gundam -} - -func (s *Taro) cut() { - println("ニッパーで切る") -} - -func (s *Taro) build() { - println("組み立てる") -} - -func (s *Taro) paint() { - println("色を塗る") -} diff --git a/template_method/1/template_method_test.go b/template_method/1/template_method_test.go deleted file mode 100644 index 33db2c3..0000000 --- a/template_method/1/template_method_test.go +++ /dev/null @@ -1,8 +0,0 @@ -package template_method - -import "testing" - -func TestTemplateMethod1(t *testing.T) { - s := &Taro{} - s.Create(s) -} diff --git a/template_method/2/template_method.go b/template_method/2/template_method.go deleted file mode 100644 index df4f033..0000000 --- a/template_method/2/template_method.go +++ /dev/null @@ -1,32 +0,0 @@ -package template_method - -// 小文字にしてプライベートにする -type kit interface { - cut() - build() - paint() -} - -type Gundam struct { - kit -} - -func (s *Gundam) Create() { - s.kit.cut() - s.kit.build() - s.kit.paint() -} - -type Taro struct{} - -func (s *Taro) cut() { - println("ニッパーで切る") -} - -func (s *Taro) build() { - println("組み立てる") -} - -func (s *Taro) paint() { - println("色を塗る") -} diff --git a/template_method/2/template_method_test.go b/template_method/2/template_method_test.go deleted file mode 100644 index b81b05a..0000000 --- a/template_method/2/template_method_test.go +++ /dev/null @@ -1,8 +0,0 @@ -package template_method - -import "testing" - -func TestTemplateMethod2(t *testing.T) { - s := &Gundam{new(Taro)} - s.Create() -} diff --git a/template_method/README.md b/template_method/README.md index e0341b6..3598198 100644 --- a/template_method/README.md +++ b/template_method/README.md @@ -19,6 +19,11 @@ - 再利用性が低い ### 例題 - -* 細かいことはその人任せるとして、ガンダムを作ってもらうことにしました -* ガンダムはパーツを切って、組み立て、色を塗ります +- ワンタイムパスワード(OTP)機能 +- OTPをユーザーに配信する方法はいくつかあります(SMS、電子メールなど) +- ただやってることは同じ + - ランダムなn桁の数字を生成します。 + - 後で確認できるように、この番号をキャッシュに保存します。 + - コンテンツを準備します。 + - 通知を送信します。 + - 指標を公開します。 \ No newline at end of file diff --git a/template_method/email.go b/template_method/email.go new file mode 100644 index 0000000..2a36f9b --- /dev/null +++ b/template_method/email.go @@ -0,0 +1,30 @@ +package template_method + +import "fmt" + +type email struct { + otp +} + +func (s *email) genRandomOTP(len int) string { + randomOTP := "1234" + fmt.Printf("EMAIL: generating random otp %s\n", randomOTP) + return randomOTP +} + +func (s *email) saveOTPCache(otp string) { + fmt.Printf("EMAIL: saving otp: %s to cache\n", otp) +} + +func (s *email) getMessage(otp string) string { + return "EMAIL OTP for login is " + otp +} + +func (s *email) sendNotification(message string) error { + fmt.Printf("EMAIL: sending email: %s\n", message) + return nil +} + +func (s *email) publishMetric() { + fmt.Printf("EMAIL: publishing metrics\n") +} diff --git a/template_method/otp.go b/template_method/otp.go new file mode 100644 index 0000000..9eef218 --- /dev/null +++ b/template_method/otp.go @@ -0,0 +1,40 @@ +package template_method + +type iOtp interface { + genRandomOTP(int) string + saveOTPCache(string) + getMessage(string) string + sendNotification(string) error + publishMetric() +} + +// type otp struct { +// } + +// func (o *otp) genAndSendOTP(iOtp iOtp, otpLength int) error { +// otp := iOtp.genRandomOTP(otpLength) +// iOtp.saveOTPCache(otp) +// message := iOtp.getMessage(otp) +// err := iOtp.sendNotification(message) +// if err != nil { +// return err +// } +// iOtp.publishMetric() +// return nil +// } + +type otp struct { + iOtp iOtp +} + +func (o *otp) genAndSendOTP(otpLength int) error { + otp := o.iOtp.genRandomOTP(otpLength) + o.iOtp.saveOTPCache(otp) + message := o.iOtp.getMessage(otp) + err := o.iOtp.sendNotification(message) + if err != nil { + return err + } + o.iOtp.publishMetric() + return nil +} diff --git a/template_method/sms.go b/template_method/sms.go new file mode 100644 index 0000000..67b76f5 --- /dev/null +++ b/template_method/sms.go @@ -0,0 +1,30 @@ +package template_method + +import "fmt" + +type sms struct { + otp +} + +func (s *sms) genRandomOTP(len int) string { + randomOTP := "1234" + fmt.Printf("SMS: generating random otp %s\n", randomOTP) + return randomOTP +} + +func (s *sms) saveOTPCache(otp string) { + fmt.Printf("SMS: saving otp: %s to cache\n", otp) +} + +func (s *sms) getMessage(otp string) string { + return "SMS OTP for login is " + otp +} + +func (s *sms) sendNotification(message string) error { + fmt.Printf("SMS: sending sms: %s\n", message) + return nil +} + +func (s *sms) publishMetric() { + fmt.Printf("SMS: publishing metrics\n") +} diff --git a/template_method/template_method.go b/template_method/template_method.go new file mode 100644 index 0000000..5a5b364 --- /dev/null +++ b/template_method/template_method.go @@ -0,0 +1,32 @@ +package template_method + +import "fmt" + +func main() { + // otp := otp{} + + // smsOTP := &sms{ + // otp: otp, + // } + + // smsOTP.genAndSendOTP(smsOTP, 4) + + // emailOTP := &email{ + // otp: otp, + // } + // emailOTP.genAndSendOTP(emailOTP, 4) + // fmt.Scanln() + smsOTP := &sms{} + o := otp{ + iOtp: smsOTP, + } + o.genAndSendOTP(4) + + fmt.Println("") + emailOTP := &email{} + o = otp{ + iOtp: emailOTP, + } + o.genAndSendOTP(4) + +} diff --git a/template_method/template_method_test.go b/template_method/template_method_test.go new file mode 100644 index 0000000..2c7b3ab --- /dev/null +++ b/template_method/template_method_test.go @@ -0,0 +1,7 @@ +package template_method + +import "testing" + +func TestTemplateMethod(t *testing.T) { + main() +}