Menu
Coddy logo textTech

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 を追加し、ファクトリ関数を更新するだけです。

challenge icon

チャレンジ

簡単

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)
}
quiz icon腕試し

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

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