607
0

מסבירים את תבנית הצופה – Observer Design Pattern

607
זמן קריאה: 3 דקות

מה זה Observer Pattern?

תבנית צופה – Observer (שמוכרת גם בשמות  Event-Subscriber, Listener)
היא תבנית עיצוב המגדירה תלות אובייקט אחד לרבים כאשר אובייקט הייחוס מחזיק רשימה של אובייקטים שמקושרים / תלויים בו וכל אחד מהם נקרא צופה בייחוס אליו.

כאשר האובייקט הראשי משנה את המצב שלו כל התלויים בו יקבלו יקבלו הודעה ויתעדכנו אוטומטית.

תוכן עניינים

 

הנושא והצופה

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

UML class diagram

הדמיה של המחלקות והאובייקטים המשתתפים בתבנית זו.
 
 

דוגמה

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

 

 

 

 

 

כך ייראה פלט הקוד:

				
					    interface ISubject
    {
        void Attach(IObserver observer);

        void Detach(IObserver observer);

        void NotifyAll();

        public void SetBidAmount(IObserver observer, double newBidAmount);
    }
				
			
				
					public class Product : ISubject
    {
        private List<IObserver> observers;
        private String productName;
        private double bidAmount;
        private IObserver observer;

        public Product(String product, double bid)
        {
            observers = new List<IObserver>();
            productName = product;
            bidAmount = bid;
        }

        public void Attach(IObserver observer)
        {
            observers.Add(observer);
        }

        public void Detach(IObserver observer)
        {
            observers.Remove(observer);
            Console.WriteLine($"Update: {observer} has withdrawn from bidding" );
        }

        public void NotifyAll()
        {
            foreach (var ob in observers)
            {
                ob.Notify(this.observer, this.productName, this.bidAmount);
            }
        }

        public void SetBidAmount(IObserver observer, double newBidAmount)
        {
            Console.WriteLine("\n*************** New bid placed ***************");
            int res = bidAmount.CompareTo(newBidAmount);
            if (res == -1)
            {
                this.observer = observer;
                this.bidAmount = newBidAmount;
                //setChanged();
                NotifyAll();
            }
            else
            {
                Console.WriteLine("New bid amount cannot be less or equal to current bid amount: " + this.bidAmount);
            }
        }
    }
				
			
				
					public interface IObserver
    {
        void Notify(IObserver observer, String productName, double bidAmount);
    }
				
			
				
					public class Bidder : IObserver
    {
        private string bidderName;

        public double bidPrice;
        public override string ToString() => bidderName;

        public Bidder(string name)
        {
            bidderName = name;
        }

        public void BidNewPrice(double price)
        {
            bidPrice = price;
        }

        public void Notify(IObserver observer, String productName, double bidAmount)
        {
            if (observer.ToString().Equals(bidderName))
            {
                Console.WriteLine($"Hello {bidderName}! \nNew bid of amount {bidAmount}$ has been placed on {productName} by you\n");
            }
            else
            {
                Console.WriteLine($"Hello {bidderName}! \nNew bid of amount {bidAmount}$ has been placed on {productName} by {observer.ToString()}\n");
            }
        }
    }
				
			
				
					public class Program
    {
        static void Main(string[] args)
        {
            Product product = new Product("75 in. Led 8K TV", 350);
            IObserver bidder1 = new Bidder("Amir");
            IObserver bidder2 = new Bidder("Ron");
            IObserver bidder3 = new Bidder("Daniel");
            product.Attach(bidder1);
            product.Attach(bidder2);
            product.Attach(bidder3);
            product.SetBidAmount(bidder1, 375);
            product.Detach(bidder2);
            product.SetBidAmount(bidder3, 400);

            Console.ReadKey();
        }
    }
				
			

מקורות וקרדיטים

Head First Design Patterns book
ויקיפדיה
Main Photo by Pawel Janiak on Unsplash
Second Photo by krakenimages on Unsplash 

אמיר שטיימן
WRITEN BY

אמיר שטיימן

Backend Engineer @Cynet
ביום יום מפתח Backend בסביבת SaaS, מיקרו סרביסים בשילוב של מערכות מבוזרות. בזמני הפנוי - לומד ומשתדרג בעולם התוכנה, אוהד מכבי חיפה, פלייסטיישן ובירה עם חברים :)
Linkedin | Twitter

כתיבת תגובה

האימייל לא יוצג באתר. שדות החובה מסומנים *