Menu
Coddy logo textTech

תבנית המצב

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

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

ב-Go, נגדיר ממשק של מצב וניצור מצבים קונקרטיים שמממשים התנהגויות שונות:

type State interface {
    Handle(d *Document) string
}

type Document struct {
    state State
}

func (d *Document) SetState(s State) {
    d.state = s
}

func (d *Document) Publish() string {
    return d.state.Handle(d)
}

כל מצב קובע מה קורה ומהו המצב הבא:

type DraftState struct{}

func (s DraftState) Handle(d *Document) string {
    d.SetState(ModerationState{})
    return "Draft submitted for moderation"
}

type ModerationState struct{}

func (s ModerationState) Handle(d *Document) string {
    d.SetState(PublishedState{})
    return "Moderation approved, now published"
}

type PublishedState struct{}

func (s PublishedState) Handle(d *Document) string {
    return "Already published"
}

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

doc := &Document{state: DraftState{}}

fmt.Println(doc.Publish())  // הטיוטה הוגשה לבדיקה
fmt.Println(doc.Publish())  // הבדיקה אושרה, כעת המסמך מפורסם
fmt.Println(doc.Publish())  // כבר פורסם

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

challenge icon

אתגר

קל

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

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

  • state.go: הגדירו ממשק מצב ואת המצבים הקונקרטיים שמייצגים כל שלב במחזור החיים של כרטיס.

    צרו ממשק TicketState עם מתודה Handle(t *Ticket) string שמעבדת את הכרטיס ועשויה להעביר אותו למצב הבא.

    ממשו שלושה מצבים:

    • OpenState: בעת הטיפול, מעביר את הכרטיס ל-InProgressState ומחזיר Ticket opened, assigning to support team
    • InProgressState: בעת הטיפול, מעביר את הכרטיס ל-ResolvedState ומחזיר Working on ticket, issue resolved
    • ResolvedState: בעת הטיפול, נשאר באותו מצב ומחזיר Ticket already resolved
  • ticket.go: צרו מבנה כרטיס שמכיל את המצב הנוכחי ומאציל לו את ההתנהגות.

    בנו מבנה Ticket עם שדה ID (מחרוזת) ושדה state (TicketState). הוסיפו את המתודות האלה:

    • SetState(s TicketState) כדי לשנות את המצב הנוכחי של הכרטיס
    • Process() string שמאצילה את הפעולה למתודת Handle של המצב הנוכחי

    צרו בנאי NewTicket(id string) *Ticket שמחזיר כרטיס שמתחיל במצב OpenState.

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

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

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

  • שורה 1: מזהה הכרטיס
  • שורה 2: מספר הפעמים לעבד את הכרטיס

לדוגמה, עבור:

TKT-001
3

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

Ticket opened, assigning to support team
Working on ticket, issue resolved
Ticket already resolved

ועבור:

TKT-500
5

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

Ticket opened, assigning to support team
Working on ticket, issue resolved
Ticket already resolved
Ticket already resolved
Ticket already resolved

ועבור:

ISSUE-42
1

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

Ticket opened, assigning to support team

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

נסו בעצמכם

package main

import (
	"fmt"
)

func main() {
	// קרא את הקלט
	var ticketID string
	var numProcesses int
	fmt.Scanln(&ticketID)
	fmt.Scanln(&numProcesses)

	// TODO: צור כרטיס חדש עם ה-ID הנתון

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

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

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

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