Menu
Coddy logo textTech

תבנית העיצוב

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

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

ב-Go, אנחנו מממשים זאת בכך שגם הטיפוס הבסיסי וגם העוטפים מממשים את אותו ממשק:

type Notifier interface {
    Send(message string) string
}

type BasicNotifier struct{}

func (b BasicNotifier) Send(message string) string {
    return "Sending: " + message
}

עוטפים Notifier נוסף בעטיפות ומוסיפים התנהגות לפני העברת הביצוע אליו או אחריה:

type TimestampDecorator struct {
    wrapped Notifier
}

func (t TimestampDecorator) Send(message string) string {
    timestamped := "[2024-01-15] " + message
    return t.wrapped.Send(timestamped)
}

type UppercaseDecorator struct {
    wrapped Notifier
}

func (u UppercaseDecorator) Send(message string) string {
    return strings.ToUpper(u.wrapped.Send(message))
}

העוצמה של Decorator טמונה בערימת כמה עטיפות כדי לשלב התנהגויות:

notifier := BasicNotifier{}
withTimestamp := TimestampDecorator{wrapped: notifier}
withBoth := UppercaseDecorator{wrapped: withTimestamp}

fmt.Println(notifier.Send("Hello"))
// שולח: Hello

fmt.Println(withBoth.Send("Hello"))
// שולח: [2024-01-15] HELLO

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

challenge icon

אתגר

קל

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

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

  • beverage.go: הגדירו את הממשק המרכזי ואת סוג הקפה הבסיסי שלכם.

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

    • Description() string: מחזירה מהו המשקה
    • Cost() float64: מחזירה את המחיר

    ממשו מבנה Coffee בתור המשקה הבסיסי שלכם. התיאור שלו צריך להיות Coffee והמחיר שלו צריך להיות 2.00.

  • decorators.go: צרו את סוגי המקשטים שמוסיפים תוספות לכל משקה.

    כל מקשט עוטף Beverage ומממש את אותו הממשק. צרו שלושה מקשטים:

    • MilkDecorator: מוסיף , Milk לתיאור ו-0.50 למחיר
    • SugarDecorator: מוסיף , Sugar לתיאור ו-0.25 למחיר
    • WhipDecorator: מוסיף , Whip לתיאור ו-0.75 למחיר

    כל מקשט צריך לקרוא למתודות של המשקה העטוף ולשפר את התוצאה.

  • main.go: בנו משקאות בהתאמה אישית באמצעות ערימה של מקשטים.

    קראו את מספר התוספות שיש להוסיף. לאחר מכן, עבור כל תוספת, קראו את הסוג שלה (milk, sugar או whip) ועטפו את המשקה הנוכחי שלכם במקשט המתאים.

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

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

  • שורה 1: מספר התוספות שיש להוסיף
  • השורות הבאות: סוג תוספת אחד בכל שורה (milk, sugar או whip)

לדוגמה, בהינתן:

2
milk
sugar

הפלט שלכם צריך להיות:

Coffee, Milk, Sugar
$2.75

ובהינתן:

3
whip
milk
milk

הפלט שלכם צריך להיות:

Coffee, Whip, Milk, Milk
$3.75

ובהינתן:

0

הפלט שלכם צריך להיות:

Coffee
$2.00

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

נסו בעצמכם

package main

import (
	"fmt"
)

func main() {
	// קראו את מספר התוספות
	var count int
	fmt.Scanln(&count)

	// התחילו עם קפה בסיסי
	var drink Beverage = &Coffee{}

	// קראו כל תוספת ועטפו את המשקה בדקורטור המתאים
	for i := 0; i < count; i++ {
		var extra string
		fmt.Scanln(&extra)

		// TODO: בהתאם לסוג התוספת, עטפו את drink בדקורטור המתאים
		// השתמשו ב-MilkDecorator עבור "milk"
		// השתמשו ב-SugarDecorator עבור "sugar"
		// השתמשו ב-WhipDecorator עבור "whip"
	}

	// TODO: הדפיסו את התיאור והעלות הסופיים
	// עצבו את העלות בתבנית $X.XX עם שתי ספרות בדיוק אחרי הנקודה העשרונית
}
quiz iconבחנו את עצמכם

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

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

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