Menu
Coddy logo textTech

デザインパターン入門

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などの振る舞いパターンへと進みます。

challenge icon

チャレンジ

簡単

デザインパターンがコードの整理にどのように役立つかを示す、シンプルな通知システムを構築しましょう!将来のレッスンで Observer や Strategy のようなパターンを簡単に拡張できる構造を作成しますが、今は、優れた OOP の原則に従う、整理されたインターフェースと型の設定に集中してください。

コードを3つのファイルに分けて整理します。

  • notifier.go: 通知システムの中核となるインターフェースと型を Define します。

    単一のメソッド Send(message string) string を持つ Notifier インターフェースを Create してください。このメソッドは確認メッセージを返します。

    2つの具象 notifier 型を Implement します。

    • EmailNotifierAddress フィールドを持ちます。その Send method は Email to [address]: [message] を返します
    • SMSNotifierPhoneNumber フィールドを持ちます。その Send method は 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: メッセージをブロードキャストし、各確認を出力する

}
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

オブジェクト指向プログラミングのすべてのレッスン

自分で練習してみよう: Goオンラインコンパイラ