Menu
Coddy logo textTech

תבנית Abstract Factory

חלק מהיחידה תכנות מונחה עצמים במסלול ה-GO של Coddy. שיעור 88 מתוך 107.

תבנית המפעל המופשט מרחיבה את תבנית המפעל באמצעות יצירת משפחות של אובייקטים קשורים בלי לציין את הסוגים הקונקרטיים שלהם. במקום פונקציית מפעל יחידה, מגדירים ממשק מפעל שכמה מפעלים קונקרטיים מממשים, וכל אחד מהם מייצר קבוצה עקבית של אובייקטים קשורים.

נניח שיש ערכת כלים לממשק משתמש שצריכה ליצור כפתורים ותיבות סימון. מערכות הפעלה שונות דורשות מימושים שונים, אבל הרכיבים חייבים לעבוד יחד באופן עקבי:

type Button interface {
    Render() string
}

type Checkbox interface {
    Check() string
}

// ממשק מפעל מופשט
type GUIFactory interface {
    CreateButton() Button
    CreateCheckbox() Checkbox
}

כל מפעל קונקרטי מייצר משפחה של רכיבים קשורים:

// משפחת 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())
}

השתמשו ב-Abstract Factory כאשר המערכת שלכם צריכה לעבוד עם כמה משפחות של מוצרים קשורים, ואתם רוצים לוודא שרכיבים מאותה משפחה ישמשו יחד. היא מורכבת יותר מ-Factory פשוטה, לכן השתמשו בה רק כשבאמת צריך לנהל משפחות מוצרים.

challenge icon

אתגר

קל

בואו נבנה מערכת לחנות רהיטים באמצעות תבנית Abstract Factory! תיצרו מפעלים שמייצרים משפחות של פריטי ריהוט קשורים: כל מפעל מייצר סגנון אחיד (מודרני או וינטג׳), וכך מובטח שכיסאות ושולחנות מאותו מפעל יתאימו זה לזה מבחינה אסתטית.

תארגנו את הקוד שלכם בשלושה קבצים:

  • furniture.go: הגדירו את ממשקי המוצרים ואת סוגי הרהיטים הקונקרטיים.

    צרו שני ממשקי מוצרים:

    • Chair עם מתודה SitOn() string
    • Table עם מתודה PlaceItems() string

    ממשו שתי משפחות רהיטים:

    • משפחה מודרנית: ModernChair מחזירה Sitting on a sleek modern chair ו-ModernTable מחזירה Placing items on a glass modern table
    • משפחת וינטג׳: VintageChair מחזירה Sitting on an ornate vintage chair ו-VintageTable מחזירה Placing items on a wooden vintage table
  • factory.go: הגדירו את ממשק המפעל המופשט ואת המפעלים הקונקרטיים.

    צרו ממשק FurnitureFactory עם שתי מתודות:

    • CreateChair() Chair
    • CreateTable() Table

    ממשו שני מפעלים קונקרטיים:

    • ModernFactory שמייצר ModernChair ו-ModernTable
    • VintageFactory שמייצר VintageChair ו-VintageTable

    צרו גם פונקציה GetFactory(style string) FurnitureFactory שמחזירה את המפעל המתאים בהתאם לסגנון (modern או vintage). עבור סגנונות לא מזוהים, ברירת המחדל תהיה ModernFactory.

  • main.go: השתמשו במפעלים שלכם כדי לרהט חדרים.

    צרו פונקציה FurnishRoom(factory FurnitureFactory) string שמשתמשת במפעל כדי ליצור כיסא ושולחן, ואז מחזירה מחרוזת מעוצבת שמציגה את שתי הפעולות בשורות נפרדות.

    קראו קלט של סגנון, קבלו את המפעל המתאים, רהטו חדר והדפיסו את התוצאה.

הקלטים הבאים יסופקו:

  • שורה 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 table

שימו לב שפונקציית FurnishRoom פועלת עם כל מפעל באמצעות הממשק. היא לא יודעת אם היא יוצרת רהיטים מודרניים או רהיטי וינטג׳. כך מובטח שכל הרהיטים בחדר מגיעים מאותה משפחה ושומרים על סגנון אחיד!

נסו בעצמכם

package main

import "fmt"

// FurnishRoom משתמשת במפעל ליצירת רהיטים ומחזירה את התוצאה
// TODO: ממשו את הפונקציה הזו
// - השתמשו במפעל כדי ליצור כיסא ושולחן
// - החזירו מחרוזת עם התוצאה של SitOn() בשורה הראשונה והתוצאה של PlaceItems() בשורה השנייה
func FurnishRoom(factory FurnitureFactory) string {
	// TODO: צרו כיסא ושולחן באמצעות המפעל
	// TODO: החזירו מחרוזת מעוצבת עם שתי הפעולות בשורות נפרדות
	return ""
}

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

	// TODO: קבלו את המפעל המתאים לפי style
	// TODO: רהטו חדר באמצעות המפעל
	// TODO: הדפיסו את התוצאה
}
quiz iconבחנו את עצמכם

השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.

כל השיעורים ביחידה תכנות מונחה עצמים

תרגלו בעצמכם: קומפיילר Go אונליין