Factory パターン
CoddyのGOジャーニー「オブジェクト指向プログラミング」セクションの一部 — レッスン 87/107。
ファクトリパターンは、オブジェクトの生成を別の関数やメソッドに委譲することで、生成ロジックを公開することなくインスタンスを作成できるようにします。インスタンスの数を制御するシングルトンとは異なり、ファクトリは入力パラメータに基づいた柔軟なオブジェクト生成に焦点を当てています。
Goにおいて、ファクトリは通常、インターフェース型を返す関数であり、統一されたAPIを通じて異なる具象型を作成できるようにします。
type Notifier interface {
Send(message string) string
}
type EmailNotifier struct{}
type SMSNotifier struct{}
func (e EmailNotifier) Send(message string) string {
return "Email: " + message
}
func (s SMSNotifier) Send(message string) string {
return "SMS: " + message
}
func NewNotifier(notifierType string) Notifier {
switch notifierType {
case "email":
return EmailNotifier{}
case "sms":
return SMSNotifier{}
default:
return EmailNotifier{}
}
}ファクトリ関数 NewNotifier は、どの具象型を作成するかという決定をカプセル化します。クライアントコードは Notifier インターフェースのみを扱い、具体的な実装については関知しません。
notifier := NewNotifier("sms")
result := notifier.Send("Hello!") // "SMS: Hello!"このパターンは、実行時の条件に基づいてオブジェクトを作成する必要がある場合、複雑な初期化ロジックを集中管理したい場合、またはクライアントコードを修正することなく新しい型を簡単に追加する必要がある場合に真価を発揮します。単にインターフェースを実装する新しい struct を追加し、ファクトリ関数を更新するだけです。
チャレンジ
簡単Factoryパターンを使用してドキュメント変換システムを構築しましょう!ターゲットとなるフォーマットに基づいて異なるドキュメントコンバーターを生成するファクトリを作成し、クライアントコードが統一されたインターフェースを通じて任意のコンバーターを操作できるようにします。
コードは2つのファイルに分けて構成します:
converter.go: コンバーターのインターフェースと具体的な実装を定義します。ドキュメントの内容を受け取り、変換された出力を返す
Convert(content string) stringメソッドを持つConverterインターフェースを作成します。3つのコンバーター型を実装します:
PDFConverter— そのConvertメソッドは"PDF: " + contentを返します。HTMLConverter— そのConvertメソッドは"HTML: <p>" + content + "</p>"を返します。MarkdownConverter— そのConvertメソッドは"MD: # " + contentを返します。
フォーマット文字列(
"pdf"、"html"、または"markdown")に基づいて適切なコンバーターを返すファクトリ関数NewConverter(format string) Converterを作成します。認識されないフォーマットの場合は、デフォルトとしてPDFConverterを返してください。main.go: ファクトリを使用してコンバーターを作成し、ドキュメントを処理します。フォーマット形式とドキュメントの内容を読み取ります。ファクトリを使用して適切なコンバーターを作成し、内容を変換して結果を出力します。
以下の入力が提供されます:
- 1行目:フォーマット形式(
"pdf"、"html"、"markdown"、またはその他) - 2行目:変換するドキュメントの内容
例えば、以下が与えられた場合:
html
Welcome to Go Programming出力は以下のようになります:
HTML: <p>Welcome to Go Programming</p>また、以下が与えられた場合:
markdown
Chapter One出力は以下のようになります:
MD: # Chapter Oneまた、以下が与えられた場合:
pdf
Annual Report 2024出力は以下のようになります:
PDF: Annual Report 2024また、以下が与えられた場合:
docx
Meeting Notes出力は以下のようになります:
PDF: Meeting Notesメインコードが特定のコンバーター型について知る必要がないことに注目してください。ファクトリにコンバーターを要求し、インターフェースを使用するだけです。これにより、クライアントコードを変更することなく、後で新しいフォーマットを簡単に追加できるようになります!
チートシート
Factoryパターンは、オブジェクトの生成を別の関数に委譲し、生成ロジックを公開せずにインスタンスを作成できるようにします。これは、入力パラメータに基づいた柔軟なオブジェクト生成に焦点を当てています。
ファクトリ関数はインターフェース型を返すため、統一されたAPIを通じて異なる具体的な型を作成できます:
type Notifier interface {
Send(message string) string
}
type EmailNotifier struct{}
type SMSNotifier struct{}
func (e EmailNotifier) Send(message string) string {
return "Email: " + message
}
func (s SMSNotifier) Send(message string) string {
return "SMS: " + message
}
func NewNotifier(notifierType string) Notifier {
switch notifierType {
case "email":
return EmailNotifier{}
case "sms":
return SMSNotifier{}
default:
return EmailNotifier{}
}
}クライアントコードはインターフェースのみを扱い、具体的な実装については関知しません:
notifier := NewNotifier("sms")
result := notifier.Send("Hello!") // "SMS: Hello!"このパターンは、実行時の条件に基づいてオブジェクトを作成する必要がある場合、複雑な初期化ロジックを一元化したい場合、またはクライアントコードを変更せずに新しい型を追加する必要がある場合に役立ちます。
自分で試してみよう
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
scanner := bufio.NewScanner(os.Stdin)
// フォーマット形式を読み込む
scanner.Scan()
format := scanner.Text()
// ドキュメントの内容を読み込む
scanner.Scan()
content := scanner.Text()
// TODO: ファクトリを使用して適切なコンバータを作成する
// TODO: コンテンツを変換して結果を出力する
fmt.Println(result)
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
1Go オブジェクト指向の基礎
外部ファイルGo ワークスペースとモジュールパッケージとインポート公開された名前と非公開の名前Go におけるオブジェクト指向入門クラスとしての構造体構造体へのメソッド定義ポインタレシーバと値レシーバ構造体の初期化コンストラクタ関数まとめ:簡易計算機8エラー処理とOOP
error インターフェースカスタムエラー型エラーラッピング (fmt.Errorf)センチネルエラーerrors.Is() と errors.As()Panic、Defer、Recover復習 - ファイルパーサー