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 を本当に管理する必要がある場合にのみ使用してください。
チャレンジ
簡単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:
ModernChairはSitting on a sleek modern chairを返し、ModernTableはPlacing items on a glass modern tableを返します。 - Vintage family:
VintageChairはSitting on an ornate vintage chairを返し、VintageTableはPlacing items on a wooden vintage tableを返します。
factory.go:Abstract factoryのinterfaceと具体的なfactoryをDefineします。2つのメソッドを持つ
FurnitureFactoryinterfaceを作成します。CreateChair() ChairCreateTable() Table
2つの具体的なfactoryをImplementします。
ModernFactory:ModernChairとModernTableを生成します。VintageFactory:VintageChairとVintageTableを生成します。
また、スタイル(
modernまたはvintage)に基づいて適切なfactoryを返すfunctionGetFactory(style string) FurnitureFactoryを作成します。認識されないスタイルの場合はModernFactoryをDefaultにします。main.go:factoryを使用して部屋に家具を配置します。factoryを使ってchairとtableを作成し、両方のactionsを別々の行に表示するformatted stringを返すfunction
FurnishRoom(factory FurnitureFactory) stringを作成します。スタイルの入力を読み取り、適切なfactoryを取得して部屋に家具を配置し、結果を出力します。
次の入力が提供されます。
- 1行目:家具のスタイル(
modern、vintage、またはその他)
例えば、次の入力が与えられた場合:
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 tableFurnishRoom 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: 結果を出力する
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
1Go オブジェクト指向の基礎
外部ファイルGo ワークスペースとモジュールパッケージとインポート公開された名前と非公開の名前Go におけるオブジェクト指向入門クラスとしての構造体構造体へのメソッド定義ポインタレシーバと値レシーバ構造体の初期化コンストラクタ関数まとめ:簡易計算機8エラー処理とOOP
error インターフェースカスタムエラー型エラーラッピング (fmt.Errorf)センチネルエラーerrors.Is() と errors.As()Panic、Defer、Recover復習 - ファイルパーサー自分で練習してみよう: Goオンラインコンパイラ