Observer design patterni.

Bugungi maqolamiz Observer design pattern haqida bo'ladi. Ko'pchilik dasturchilar o'zimiz bilmagan holda ko'p yillar davomida ushbu design patternni ishlatib kelganmiz. Micrososft Asp.Net WebForms, Microsoft Asp.Net MVC, Windows Application, GWT(Google Web Toolkit), Java Swing, ushbularni ishlatgan bo'lsangiz siz ham Observer design patternining qulayliklaridan foydalangansiz.

Maqola uch qismdan iborat bo'ladi. Birinchi qismda GOF tomonidan berilgan ta'birni keltiramiz undan tashqari ba'zi foyda va kamchiliklarga ham e'tibor berib o'tamiz. Ikkinchi qismda aniq bir muammoni muhokama qilib, ushbu design pattern yordamida unga yechim topamiz. Uchinchi qismda esa implementatsiya qilamiz.

Birinchi qism. Observer design patterni qachon ishlatiladi? Biri boshqasidan taqozo qilgan, birga-ko'p usulida bog'langan obyektlardan iborat tizimda, agar obyekt o'z holatini o'zgartirsa unga buysunuvchi boshqa obyektlar ham o'z holatini avtomatik o'zgartishi lozim bo'lgan holatlarda ishlatiladi. Quyidagi rasmda ushbu holatga mos keluvchi diagramma berilgan.


Observer obyekt doim Subject obyektdan taqozo qiladi shu sabab doimo uni kuzatib turadi. Agar Subject da biror o'zgarish bo'lsa darrov o'zidagi ma'lumotni yangilaydi. Bu jarayonga quyidagicha erishiladi. ConcreteSubject da biror o'zgarish bo'lsa, u Notify() metodni chaqiradi va unga buysunuvchi Observer larga o'zgarish bo'lgani haqida habar beradi. Bir Subject birdan ko'p kuzatuvchilarga ega bo'lishi mumkin. Buning uchun Attach() va Detach() metodlaridan foydalaniladi. Ushbu design patternda P2I prinsipi juda go'zallik bilan amalga oshirilgan. Ya'ni abstrakt darajada saqlanadigan biror bir Subject unga bo'glanda Observer ichida nima borligidan bexabar bo'ladi. U faqat Notify() chaqirishni biladi holos. Undan Subjectning o'zi abstarkt darajada joylashgani sabab undan meros olgan classlar Attach() va Detach() metodlarni ham meros oladi. Rasmda ko'rinib tuganidek, subject obyekti o'z ichida barcha observer obyektlarni saqlaydi. Open/Closed prinsipiga asosan turli yangi ConcreteSubject larni qo'shib borishimiz mumkin. Yanada tushunarliroq bo'lishi uchun kodga qarashingiz so'rayman. Ikkinchi qism Muammo: Tassavur qiling, pochta xizmati orqali Qo'qondan Shovotga yuk jo'natildi. Yukning manzilga yetgunga qadar vaqtinchalik to'xtagan manzillari haqidagi ma'lumotlar ketma-ketligini ko'rsating. Yuk 2 hil statusga ega bo'lishi mumkin. "Ro'yhatdan o'tdi" va "Jo'natildi". Quyidagi rasmda ushbu jarayonning umumiy ko'rinishi berilgan.

Rasmdan ko'rinib turibdiki yuk Qo'qondan yo'lga chiqqan, Toshkent shahriga kelgan va ro'yhatdan o'tgan ma'lum vaqtdan so'ng yana jo'natilgan. Va Jizzahga yetib borguncha "Jo'natildi" statusi ostida bo'lgan. Maqsadimiz, har safar yuk o'z statusini o'zgartirganda bu haqida foydalanuvchini habardor qilish. Buning uchun Observer design patternidan foydalanamiz. Endi ushbu tizim uchun ishlatiladigan obyektlarni muhokama qilamiz va Oberver design patterndagi mos obyektlar bilan o'rin almashtiramiz. Subject ga mos Yuk classni bo'lishi aniq. Yuk nom, manzil, va status kabi hususiyatga ega bo'lsin. Yuk ning holat o'zgarishini kuzatuvchi Observer yaratamiz uning nomi YukReporter bo'lsin. Demak:


Uchinchi qism. Diagramma berilgan classlarni birma-bir yozib chiqamiz. IObserver interface.

    //kuzatuvchi uchun interface
    public interface IObserver
    {
        void Update();
    }

Subject abstrakt classi.

    //subject abstract classi
    public abstract class Subject
    {
        //kuzatuvchilarning ro'yhati
        private readonly List<IObserver> _observers;
        //kunstruktor
        protected Subject()
        {
            _observers = new List<IObserver>();
        }
        //kuzatuvchini ro'yhatdan o'tqazish
        public void Attach(IObserver observer)
        {
            _observers.Add(observer);
        }
        //kuatuvchini ro'yhatdan chiqarish
        public void Detach(IObserver observer)
        {
            _observers.Remove(observer);
        }
        //obyektdagi o'zgarishlardan kuzatuvchini habardor qiladi
        public void Notify()
        {
            foreach (IObserver observer in _observers)
            {
                observer.Update();
            }
        }
    }

Yuk classi.

    //konkret subject obyekt
    public class Yuk : Subject
    {
        public string Name { get; set; }
        public string Manzil { get; set; }
        private string _status;
        //faqat status o'zgarganda kuzatuvchiga habar ketadi
        public string Status
        {
            get { return _status; }
            set
            {
                _status = value;
                Notify();
            }
        }
    }

Yukni kuzatib boruvchi YukReporter.

//konkret kuzatuvchi
public class YukReporter : IObserver
    {
        //kuatilayotgan obyekt
        private readonly Yuk _yuk;
        public YukReporter(Yuk yuk)
        {
            _yuk = yuk;
        }
        //obyekt o'zgarish haqida habar kelgan, ekrandagi ma'lumotni yangilaydi
        public void Update()
        {
            if (_yuk != null)
            {
                Console.WriteLine("Yuk nomi: {0} -----------------------", _yuk.Name);
                Console.WriteLine("Manzil: {0}   Status: {1}", _yuk.Manzil, _yuk.Status);
            }
        }
    }

Ushbu kodni ishga tushuruvchi main metod.

static void Main(string[] args)
        {
            //manzillar ro'yhati
            string[] manzillar = { "Qo'qon", "Toshkent", "Toshkent", "Jizzah", "Jizzah", "Qarshi", "Qarshi", "Shovot" };
            //statuslar
            string[] statuslar = { "Jo'natildi", "Ro'yhatdan o'tdi", "Jo'natildi", "Ro'yhatdan o'tdi", "Jo'natildi", "Ro'yhatdan o'tdi", "Jo'natildi", "Ro'yhatdan o'tdi" };
            Yuk yuk = new Yuk()
            {
                Name = "Iphone 5"
            };
            //kuzatuvchi
            IObserver observer = new YukReporter(yuk);
            //kuzatuvchi ro'yhatdan o'tdi
            yuk.Attach(observer);
            //yuk yo'lga chiqdi
            for (int i = 0; i < statuslar.Length; i++)
            {
                yuk.Manzil = manzillar[i];
                yuk.Status = statuslar[i];
                Thread.Sleep(1000);
            }
            //kuzatuvchi ro'yhatdan chiqarildi.
            yuk.Detach(observer);
        }
    }
             

Ushbu uslubning kamchiliklaridan biri, agar observer detach qilinmasa o'zaro bir-biriga bog'langan obyekt soni ko'payib ketishi mumkin natijada esa xotira bilan bo'gliq muammolar kelib chiqadi. Buning oldini olish uchun .Net Framework ning 4-versiyasidan boshlanga IObserver<> dan foydalanagan ma'qul. To'liq kod bilan ushbu link orqali tanishishingiz mumkin.

Manba:


JONNY

Muallif haqida

JONNY Arduino, Java, C#, Android, Windows, Linux, Debian, Javascript. O'zbekistonni rivojlantiramiz! Dasturlash orqali vatanimizni yangi marralarga olib chiqamiz.


Blogdagi so‘nggi maqolalar:


Birinchi bo‘ling!

Iltimos, fikr bildirish uchun saytga kiring yoki ro‘yxatdan o‘ting!