JavaRush /Java Blogu /Random-AZ /Müşahidəçi şablonu

Müşahidəçi şablonu

Qrupda dərc edilmişdir
The Gang of Four-un yazdığı kimi (4 yüksək səviyyəli tərtibatçının “Obyekt yönümlü dizayn nümunələri” kitabına istinad edərək), bu nümunənin məqsədi obyektlər arasında birdən çox asılılığı elə müəyyən etməkdir ki, bir obyektin vəziyyəti dəyişir, ondan asılı olanların hamısı bu barədə məlumatlandırılır və avtomatik olaraq yenilənir. Bu nümunə də deyilir: Dependents (tabe olanlar) və ya Publish-Subscribe (naşir - abunəçi). Amma gəlin bunu katolik kilsəsinin nümunəsindən istifadə edərək anlamağa çalışaq :) Onun bu kilsənin təlimlərinə inanan ardıcılları var. Hər hansı yeni dogmalar (məcburi inanclar) və daha çox ortaya çıxanda, bu insanlar onlar haqqında bilməlidirlər. Bəs bu nümunədən istifadə edərək bunu proqramlaşdırma dilində necə təsvir etmək olar? 1. Bizdə “kilsənin səsi” (keçmiş katedranın yayımı zamanı kilsənin özü və ya Papa), yəni kilsədə xəbərləri elan edən müəyyən yayımçı və ya mövzu var. 2. Bu kilsənin parishionerləri, yəni mühüm hadisələrdən xəbərdar olmaq istəyən bəzi müşahidəçilər var. Müvafiq olaraq, bu gün 1,3 milyard parishioner ola bilər, sabah isə az və ya çox ola bilər. Və yalnız bu kilsədə olanları xəbərdar etmək lazımdır (yenidən ateistləri narahat etməyə ehtiyac yoxdur :). Beləliklə, bütün bunları belə ifadə etmək olar: Bir kilsə var ki, öz sürüsünə bir şey haqqında danışacaq, orada qeydiyyatdan keçə və ya əksinə, onu tərk edə bilərsiniz:
public interface Church {
    void registerParishioner(Parishioner parishioner);
    void removeParishioner(Parishioner parishioner);
    void notifyParishioners();
}
Bu üsulların tətbiqi ilə xüsusi bir Katolik Kilsəsi, həmçinin xəbərlər və bu xəbərin yayımlanmalı olduğu insanların siyahısı var:
public class CatholicChurch implements Church {
    private List<parishioner> parishioners;
    private String newsChurch;

    public CatholicChurch() {
        parishioners = new ArrayList<>();
    }

    public void setNewsChurch(String news) {
        this.newsChurch = news;
        notifyParishioners();
    }

    @Override
    public void registerParishioner(Parishioner parishioner) {
        parishioners.add(parishioner);
    }

    @Override
    public void removeParishioner(Parishioner parishioner) {
        parishioners.remove(parishioner);
    }

    @Override
    public void notifyParishioners() {
        for (Parishioner parishioner : parishioners)
            parishioner.update(newsChurch);
    }
}
Kilsəyə girə və ya çıxa bilən bir parishioner var (şifrəni sadələşdirmək üçün yalnız onun daxil olmasına icazə verəcəyik :)
public class Parishioner {

    private String name;

    public Parishioner(String name, Church church) {
        this.name = name;
        church.registerParishioner(this);
    }

    void update(String newsChurch) {
        System.out.println(name + "узнал новость: " + newsChurch);
    }
}
Müvafiq olaraq, belə işləyəcək:
public class Main {
    public static void main(String[] args) {
        var catholicChurch = new CatholicChurch();

        new Parishioner("Мартин Лютер", catholicChurch);
        new Parishioner("Жан Кальвин", catholicChurch);

        catholicChurch.setNewsChurch("Инквизиция была ошибкой... месса Mea Culpa 12 марта 2000 года");
    }
}
və proqramın nəticəsi:
Мартин Лютер узнал новость: Инквизиция была ошибкой... месса Mea Culpa 12 марта 2000 года
Жан Кальвин узнал новость: Инквизиция была ошибкой... месса Mea Culpa 12 марта 2000 года
Bunlar. Kilsədə xəbər çıxan kimi, bu kilsənin qeydiyyatdan keçmiş üzvləri sırasına daxil olan hər kəs bu barədə məlumatlandırılacaq. Bu tətbiqin çatışmazlıqları nələrdir: 1. Birincisi, qeydiyyatdan keçib xəbər ala biləcəyiniz interfeys təkcə bu kilsəyə aid ola bilməz (bu tələb oluna bilər). Buna görə də, bunu dərhal ayrı bir Müşahidə edilə bilən interfeysə köçürmək mümkün olardı. 2. Eyni şey kilsə parishionerləri ilə də edilə bilər, yəni yeniləmə metodunu ayrıca interfeysə köçürün və istədiyiniz parishioner üçün həyata keçirin. Onda bu üsul ümumiyyətlə Katolik Kilsəsinin parishionları tərəfindən deyil, məsələn, elflərin varlığında yaşayanlar tərəfindən istifadə edilə bilər ("Təkbuynuzluya gedən yol" hərəkatı deməkdir). Bunlar. yeniləmə metodu ilə Observer interfeysi yaradın. Sonda nə olacaq:
interface Observable {
    void registerObserver(Observer o);
    void removeObserver(Observer o);
    void notifyObservers();
}
public class CatholicChurch implements Observable {
    private List<observer> parishioners;
    private String newsChurch;

    public CatholicChurch() {
        parishioners = new ArrayList<>();
    }

    public void setNewsChurch(String news) {
        this.newsChurch = news;
        notifyObservers();
    }

    @Override
    public void registerObserver(Observer o) {
        parishioners.add(o);
    }

    @Override
    public void removeObserver(Observer o) {
        parishioners.remove(o);
    }

    @Override
    public void notifyObservers() {
        for (Observer o : parishioners)
            o.update(newsChurch);
    }
}
interface Observer {
    void update (String news);
}
public class Parishioner implements Observer {
    private String name;

    public Parishioner(String name, Observable o) {
        this.name = name;
        o.registerObserver(this);
    }

    @Override
    public void update(String news) {
        System.out.println(name + " узнал новость: " + news);
    }
}
Beləliklə: Kilsə ilə parishionerlər arasında "əlaqəni zəiflətdik", təbii olaraq yalnız proqramlaşdırmada yaxşıdır :) Mövzuda (katolik kilsəsi) yalnız dinləyicilərin (parishioners) siyahısı var və xəbər (dəyişikliklər) qəbul edərkən bu xəbəri yayımlayır. dinləyicilərinə. İndi siz istənilən başqa qurum yarada bilərsiniz (məsələn, protestant kilsəsi) və xəbərləri “sizin” dinləyicilərinizə yayımlaya bilərsiniz. Siz həmçinin nəzərə almalısınız ki, 2-ci sinif verilənləri (daha doğrusu, Müşahidə olunan sinif və Müşahidəçi interfeysi) java.util java paketində mövcud idi, lakin indi onlar java 9 (https://docs.oracle. com/en/java/javase/15/ docs/api/java.base/java/util/Observable.html): Köhnəlmişdir. Bu sinif və Müşahidəçi interfeysi köhnəlmişdir. Observer və Observable tərəfindən dəstəklənən hadisə modeli olduqca məhduddur, Müşahidə edilə bilən tərəfindən çatdırılan bildirişlərin sırası dəqiqləşdirilməmişdir və vəziyyət dəyişiklikləri bildirişlərlə təkbətək yazışmalarda deyil. Daha zəngin hadisə modeli üçün java.beans paketindən istifadə etməyi düşünün. Mövzular arasında etibarlı və nizamlı mesajlaşma üçün java.util.concurrent paketində paralel məlumat strukturlarından birini istifadə etməyi düşünün. Reaktiv axın tərzi proqramlaşdırması üçün Flow API-ə baxın. Buna görə də onlardan istifadə etməyə ehtiyac yoxdur. Və bunun əvəzinə başqalarından istifadə edə bilərsiniz, lakin nümunənin mahiyyəti dəyişməyəcək. Məsələn, java.beans paketindən PropertyChangeListener (artıq yazılmış əlavə sinifləri yazmamaq üçün) istifadə etməyə çalışaq. Görək necə olacaq: fənn sinfi:
public class CatholicChurch {
    private String news;
    // используя support мы можем добавлять or удалять наших прихожан (слушателей)
    private PropertyChangeSupport support;

    public CatholicChurch() {
        support = new PropertyChangeSupport(this);
    }
    public void addPropertyChangeListener(PropertyChangeListener pcl) {
        support.addPropertyChangeListener(pcl);
    }

    public void removePropertyChangeListener(PropertyChangeListener pcl) {
        support.removePropertyChangeListener(pcl);
    }

    public void setNews(String value) {
        support.firePropertyChange("news", this.news, value);
        this.news = value;
    }
}
və dinləyici sinfi:
public class Parishioner implements PropertyChangeListener {
    private String name;

    public Parishioner(String name) {
        this.name = name;
    }

    public void propertyChange(PropertyChangeEvent evt) {
        this.setNews((String) evt.getNewValue());
    }

    public void setNews(String news) {
        System.out.println(name + " узнал новость: " + news);
    }
}
Aşağıdakı kodu yerinə yetirsək:
public static void main(String[] args) {
    CatholicChurch observable = new CatholicChurch();

    observable.addPropertyChangeListener(new Parishioner("Мартин Лютер"));
    observable.addPropertyChangeListener(new Parishioner("Жан Кальвин"));

    observable.setNews("Дева Мария имеет непорочное зачатие... булла Ineffabilis Deus... 8 декабря 1854 года Папа Пий IX");
    observable.setNews("Папа непогрешим... не всегда конечно, а только когда транслирует учение церкви ex cathedra... Первый Ватиканский собор 1869 год");
}
Aşağıdakı nəticəni alırıq:
Martin Lüter xəbəri öyrəndi: Bakirə Məryəm qüsursuz hamiləlikdədir... buğa İneffabilis Deus... 8 dekabr 1854-cü il Papa IX Pius Con Kalvin xəbəri öyrəndi: Məryəm qüsursuz hamiləlikdədir... Buğa İneffabilis Deus ... 8 dekabr 1854-cü il Papa IX Pius Martin Lüter xəbəri öyrəndi: Papa məsumdur... əlbəttə ki, həmişə deyil, ancaq kilsənin keçmiş kilsəsinin təlimlərini yayımlayanda... İlk Vatikan Şurası 1869 Con Kalvin öyrəndi. xəbərlər: Papa məsumdur... əlbəttə ki, həmişə deyil, ancaq kilsənin keçmiş kilsəsinin tədrisini yayımlayanda... Birinci Vatikan Şurası 1869
Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION