Menu
Coddy logo textTech

Abstract Factory パターン

CoddyのGOジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 88/107。

Abstract Factoryパターンは、具体的な型を指定せずに関連するオブジェクトのfamiliesをcreatingすることで、Factoryパターンを拡張します。単一のfactory functionの代わりに、複数の具体的なfactoryがimplementするfactory interfaceをDefineし、それぞれが関連するオブジェクトの一貫したセットを生成します。

ボタンとチェックボックスを作成する必要があるUIツールキットを考えてみましょう。異なるオペレーティングシステムには異なる実装が必要ですが、コンポーネントは一貫して連携して動作しなければなりません。

type Button interface {
    Render() string
}

type Checkbox interface {
    Check() string
}

// 抽象ファクトリインターフェース
type GUIFactory interface {
    CreateButton() Button
    CreateCheckbox() Checkbox
}

各具象 factory は、関連するコンポーネントの family を生成します:

// Windows ファミリー
type WindowsButton struct{}
func (w WindowsButton) Render() string { return "Windows Button" }

type WindowsCheckbox struct{}
func (w WindowsCheckbox) Check() string { return "Windows Checkbox" }

type WindowsFactory struct{}
func (w WindowsFactory) CreateButton() Button { return WindowsButton{} }
func (w WindowsFactory) CreateCheckbox() Checkbox { return WindowsCheckbox{} }

// Mac ファミリー
type MacButton struct{}
func (m MacButton) Render() string { return "Mac Button" }

type MacCheckbox struct{}
func (m MacCheckbox) Check() string { return "Mac Checkbox" }

type MacFactory struct{}
func (m MacFactory) CreateButton() Button { return MacButton{} }
func (m MacFactory) CreateCheckbox() Checkbox { return MacCheckbox{} }

クライアントコードはファクトリインターフェースと連携し、具体的な実装から独立したまま動作します。

func BuildUI(factory GUIFactory) {
    button := factory.CreateButton()
    checkbox := factory.CreateCheckbox()
    fmt.Println(button.Render(), checkbox.Check())
}

システムが関連する複数の製品の families を扱う必要があり、同じ family のコンポーネントが一緒に使用されるようにしたい場合は、Abstract Factory を使用します。これは単純な Factory よりも複雑なので、製品の families を本当に管理する必要がある場合にのみ使用してください。

challenge icon

チャレンジ

簡単

Abstract Factory パターンを使って家具店システムを構築しましょう!関連する家具のfamiliesを生成するfactoryを作成します。各factoryは一貫したスタイル(ModernまたはVintage)を生成し、同じfactoryのchairとtableが美的に調和するようにします。

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

  • furniture.go:製品のinterfaceと具体的な家具の型をDefineします。

    2つの製品interfaceを作成します。

    • Chair:メソッド SitOn() string を持つ
    • Table:メソッド PlaceItems() string を持つ

    2つの家具のfamilyをImplementします。

    • Modern family:ModernChairSitting on a sleek modern chair を返し、ModernTablePlacing items on a glass modern table を返します。
    • Vintage family:VintageChairSitting on an ornate vintage chair を返し、VintageTablePlacing items on a wooden vintage table を返します。
  • factory.go:Abstract factoryのinterfaceと具体的なfactoryをDefineします。

    2つのメソッドを持つ FurnitureFactory interfaceを作成します。

    • CreateChair() Chair
    • CreateTable() Table

    2つの具体的なfactoryをImplementします。

    • ModernFactoryModernChairModernTable を生成します。
    • VintageFactoryVintageChairVintageTable を生成します。

    また、スタイル(modern または vintage)に基づいて適切なfactoryを返すfunction GetFactory(style string) FurnitureFactory を作成します。認識されないスタイルの場合は ModernFactory をDefaultにします。

  • main.go:factoryを使用して部屋に家具を配置します。

    factoryを使ってchairとtableを作成し、両方のactionsを別々の行に表示するformatted stringを返すfunction FurnishRoom(factory FurnitureFactory) string を作成します。

    スタイルの入力を読み取り、適切なfactoryを取得して部屋に家具を配置し、結果を出力します。

次の入力が提供されます。

  • 1行目:家具のスタイル(modernvintage、またはその他)

例えば、次の入力が与えられた場合:

modern

出力は次のようになります。

Sitting on a sleek modern chair
Placing items on a glass modern table

また、次の入力が与えられた場合:

vintage

出力は次のようになります。

Sitting on an ornate vintage chair
Placing items on a wooden vintage table

さらに、次の入力が与えられた場合:

rustic

出力は次のようになります。

Sitting on a sleek modern chair
Placing items on a glass modern table

FurnishRoom functionがinterfaceを通じて任意のfactoryと動作することに注目してください。このfunctionは、ModernまたはVintageの家具をcreatingしているかどうかを認識しません。これにより、部屋内のすべての家具が同じfamilyから提供され、一貫したスタイルが維持されます。

自分で試してみよう

package main

import "fmt"

// FurnishRoomはファクトリーを使用して家具を作成し、結果を返します
// TODO: この関数を実装する
// - ファクトリーを使用して椅子とテーブルを作成する
// - 1行目にSitOn()の結果、2行目にPlaceItems()の結果を含む文字列を返す
func FurnishRoom(factory FurnitureFactory) string {
	// TODO: ファクトリーを使用して椅子とテーブルを作成する
	// TODO: 両方のアクションを別々の行にしたフォーマット済み文字列を返す
	return ""
}

func main() {
	var style string
	fmt.Scanln(&style)

	// TODO: styleに基づいて適切なファクトリーを取得する
	// TODO: ファクトリーを使用して部屋に家具を配置する
	// TODO: 結果を出力する
}
quiz icon腕試し

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

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

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