デザインパターン入門
CoddyのGOジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 85/107。
デザインパターンとは、ソフトウェア設計で生じる一般的な問題に対する再利用可能な解決策です。直接コピーして使うコードではなく、特定の課題を解決するために、型とその相互作用をどのように構成するかを導くテンプレートです。
デザインパターンは通常、次の3つのカテゴリに分類されます:
| カテゴリ | 目的 | 例 |
|---|---|---|
| 生成 | オブジェクトの生成メカニズム | Singleton, Factory, Builder |
| 構造 | 型を組み合わせてより大きな構造を構成する | Adapter, Decorator, Composite |
| 振る舞い | オブジェクト間の通信 | Observer, Strategy, Command |
Goでは、デザインパターンは従来のOOP言語の場合とは異なる形になります。
クラスや継承を使わずに、Go は interfaces、構造体の埋め込み、コンポジションを使ってパターンを実装します。たとえば、Java では抽象クラスを使うような場合に、Go ではインターフェースを使います。C++ では継承を使うような場合に、Go では埋め込みを使います。
パターンを学ぶと、よくある問題を認識し、他の開発者と効果的に解決策を共有できるようになります。誰かが「ここではStrategyパターンを使おう」と言えば、チーム全体が長い説明なしにそのアプローチを理解できます。
これからのレッスンでは、Goでいくつかの基本的なパターンを実装します。まずSingletonやFactoryなどの生成パターンから始め、その後ObserverやStrategyなどの振る舞いパターンへと進みます。
チャレンジ
簡単デザインパターンがコードの整理にどのように役立つかを示す、シンプルな通知システムを構築しましょう!将来のレッスンで Observer や Strategy のようなパターンを簡単に拡張できる構造を作成しますが、今は、優れた OOP の原則に従う、整理されたインターフェースと型の設定に集中してください。
コードを3つのファイルに分けて整理します。
notifier.go: 通知システムの中核となるインターフェースと型を Define します。単一のメソッド
Send(message string) stringを持つNotifierインターフェースを Create してください。このメソッドは確認メッセージを返します。2つの具象 notifier 型を Implement します。
EmailNotifier:Addressフィールドを持ちます。そのSendmethod はEmail to [address]: [message]を返しますSMSNotifier:PhoneNumberフィールドを持ちます。そのSendmethod はSMS to [phone]: [message]を返します
dispatcher.go: インターフェースを通じて任意の notifier と連携する dispatcher を Create します。Notifierインターフェースのスライスを holds するNotificationDispatcher構造体を Build します。次のメソッドを追加します。AddNotifier(n Notifier):notifier を登録するBroadcast(message string) []string:登録されたすべての notifier を通じて message を送信し、すべての confirmation 文字列のスライスを返す
また、initialized された dispatcher を returns する
NewNotificationDispatcher()constructor も Create します。main.go: notifier を設定し、message を broadcast します。Create する notifier の count を Read します。各 notifier について、その type(
emailまたはsms)と destination(address または phone number)を Read します。それぞれを dispatcher に add します。次に、broadcast する message を Read します。それをすべての notifier を通じて送信し、各 confirmation をそれぞれ別の行に print します。
次の入力が提供されます。
- 1行目:notifier の number
- 各 notifier:type(
emailまたはsms)、続いて destination - 最終行:broadcast する message
例えば、次の入力が与えられた場合:
3
email
alice@example.com
sms
555-1234
email
bob@example.com
Server maintenance at midnight出力は次のようになります。
Email to alice@example.com: Server maintenance at midnight
SMS to 555-1234: Server maintenance at midnight
Email to bob@example.com: Server maintenance at midnightまた、次の入力が与えられた場合:
2
sms
555-9999
sms
555-0000
Meeting canceled出力は次のようになります。
SMS to 555-9999: Meeting canceled
SMS to 555-0000: Meeting canceledこの構造は、インターフェースによって柔軟で拡張可能な設計が実現することを示しています。dispatcher は特定の notifier 型について知りません。単に、それらが Send できることだけを知っています。これが、Observer や Strategy のようなパターンが基盤とする仕組みです!
自分で試してみよう
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
func main() {
reader := bufio.NewReader(os.Stdin)
// ノティファイアの数を読み取る
countStr, _ := reader.ReadString('\n')
count, _ := strconv.Atoi(strings.TrimSpace(countStr))
// 新しいディスパッチャーを作成する
dispatcher := NewNotificationDispatcher()
// 各ノティファイアを読み取り、ディスパッチャーに追加する
for i := 0; i < count; i++ {
notifierType, _ := reader.ReadString('\n')
notifierType = strings.TrimSpace(notifierType)
destination, _ := reader.ReadString('\n')
destination = strings.TrimSpace(destination)
// TODO: タイプに基づいて適切なノティファイアを作成する
// そしてディスパッチャーに追加する
// Hint: notifierType が "email" または "sms" かどうかを確認する
}
// ブロードキャストするメッセージを読み取る
message, _ := reader.ReadString('\n')
message = strings.TrimSpace(message)
// TODO: メッセージをブロードキャストし、各確認を出力する
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
1Go オブジェクト指向の基礎
外部ファイルGo ワークスペースとモジュールパッケージとインポート公開された名前と非公開の名前Go におけるオブジェクト指向入門クラスとしての構造体構造体へのメソッド定義ポインタレシーバと値レシーバ構造体の初期化コンストラクタ関数まとめ:簡易計算機8エラー処理とOOP
error インターフェースカスタムエラー型エラーラッピング (fmt.Errorf)センチネルエラーerrors.Is() と errors.As()Panic、Defer、Recover復習 - ファイルパーサー自分で練習してみよう: Goオンラインコンパイラ