Menu
Coddy logo textTech

תבנית Observer

חלק מהיחידה תכנות מונחה עצמים במסלול ה-Java של Coddy. שיעור 68 מתוך 87.

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

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

import java.util.ArrayList;
import java.util.List;

interface Observer {
    void update(String message);
}

class NewsPublisher {
    private List<Observer> subscribers = new ArrayList<>();
    
    public void subscribe(Observer observer) {
        subscribers.add(observer);
    }
    
    public void unsubscribe(Observer observer) {
        subscribers.remove(observer);
    }
    
    public void publish(String news) {
        for (Observer subscriber : subscribers) {
            subscriber.update(news);
        }
    }
}

class EmailSubscriber implements Observer {
    private String email;
    
    public EmailSubscriber(String email) {
        this.email = email;
    }
    
    public void update(String message) {
        System.out.println("Email to " + email + ": " + message);
    }
}

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

NewsPublisher publisher = new NewsPublisher();
publisher.subscribe(new EmailSubscriber("alice@mail.com"));
publisher.subscribe(new EmailSubscriber("bob@mail.com"));

publisher.publish("Breaking news!");
// פלט:
// אימייל אל alice@mail.com: חדשות מתפרצות!
// אימייל אל bob@mail.com: חדשות מתפרצות!

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

challenge icon

אתגר

קל

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

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

  • Observer.java: הגדירו את הממשק Observer שכל המשקיעים יממשו. עליו להצהיר על מתודה אחת בלבד: update(String stockName, double price), שבה צופים משתמשים כדי לקבל התראות על שינויים במחיר.
  • StockTicker.java: צרו את מחלקת הנושא, שמתחזקת רשימה של צופים ומודיעה להם על שינויים במחיר. למחלקה StockTicker שלכם צריכים להיות:

    שדה String פרטי עבור שם המניה (נקבע באמצעות הבנאי).

    שדה double פרטי עבור המחיר הנוכחי (בתחילה 0).

    רשימה פרטית לשמירת צופים שנרשמו.

    מתודת subscribe(Observer observer) שמוסיפה צופה לרשימה.

    מתודת unsubscribe(Observer observer) שמסירה צופה מהרשימה.

    מתודת setPrice(double price) שמעדכנת את המחיר ולאחר מכן מודיעה לכל הצופים באמצעות קריאה למתודת update שלהם עם שם המניה והמחיר החדש.

  • Investors.java: צרו שני סוגים שונים של משקיעים שמממשים את הממשק Observer:

    DayTrader - כולל שדה name פרטי שנקבע באמצעות הבנאי. בעת קבלת עדכון, הוא מדפיס [name] received alert: [stockName] is now $[price] - Making quick trade!

    LongTermInvestor - כולל שדה name פרטי שנקבע באמצעות הבנאי. בעת קבלת עדכון, הוא מדפיס [name] received alert: [stockName] is now $[price] - Holding steady.

    עצבו את המחיר עם שתי ספרות אחרי הנקודה העשרונית.

  • Main.java: חברו את מערכת הצופים שלכם! תקבלו שלושה קלטים: שם המניה (String), עדכון המחיר הראשון (double) ועדכון המחיר השני (double).

    צרו StockTicker עם שם המניה הנתון. צרו DayTrader בשם "Alice" ו-LongTermInvestor בשם "Bob", ורשמו את שניהם לטיקר.

    קבעו את המחיר לערך הקלט הראשון (כל הצופים יקבלו התראה). לאחר מכן בטלו את הרישום של Alice. לבסוף, קבעו את המחיר לערך הקלט השני (הפעם רק Bob אמור לקבל התראה).

תקבלו שלושה קלטים לפי הסדר: שם המניה (String), המחיר הראשון (double), המחיר השני (double).

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

נסו בעצמכם

import java.util.Scanner;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        // קראו את הקלטים
        String stockName = scanner.nextLine();
        double firstPrice = scanner.nextDouble();
        double secondPrice = scanner.nextDouble();
        
        // TODO: צרו StockTicker עם שם המניה הנתון
        
        // TODO: צרו DayTrader בשם "Alice"
        
        // TODO: צרו LongTermInvestor בשם "Bob"
        
        // TODO: רשמו גם את Alice וגם את Bob למעקב אחר הטיקר
        
        // TODO: הגדירו את המחיר ל-firstPrice (שני הצופים יקבלו הודעה)
        
        // TODO: בטלו את המינוי של Alice
        
        // TODO: הגדירו את המחיר ל-secondPrice (רק Bob יקבל הודעה)
        
        scanner.close();
    }
}
quiz iconבחנו את עצמכם

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

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

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