JavaRush /مدونة جافا /Random-AR /قالب المراقب

قالب المراقب

نشرت في المجموعة
كما كتبت Gang of Four (بالإشارة إلى كتاب "أنماط التصميم الموجهة للكائنات" من تأليف 4 من كبار المطورين)، فإن الغرض من هذا النمط هو تحديد تبعية واحد إلى متعدد بين الكائنات بطريقة أنه عندما تتغير حالة كائن واحد، ويتم إخطار جميع المعتمدين عليه بهذا الأمر ويتم تحديثهم تلقائيًا. يُسمى هذا النمط أيضًا: المُعالون (المرؤوسون) أو النشر-الاشتراك (الناشر - المشترك). لكن دعونا نحاول معرفة ذلك باستخدام مثال الكنيسة الكاثوليكية :) لديها أتباع يؤمنون بتعاليم هذه الكنيسة. وعندما تظهر أي عقائد جديدة (عقائد إلزامية) وأكثر، ينبغي أن يعرفها هؤلاء الناس. ولكن كيف يمكن وصف ذلك بلغة برمجة باستخدام هذا النمط؟ 1. لدينا "صوت الكنيسة" (الكنيسة نفسها أو البابا عند البث خارج الكنيسة)، أي مذيع أو موضوع معين يعلن الأخبار في الكنيسة. 2. هناك أبناء رعية هذه الكنيسة، أي بعض المراقبين الذين يريدون أن يكونوا على علم بالأحداث المهمة. وبناء على ذلك، قد يكون هناك اليوم 1.3 مليار من أبناء الرعية، وغدا قد يكون هناك أكثر أو أقل. وما عليك سوى إخطار الموجودين في هذه الكنيسة (لا داعي لإزعاج الملحدين مرة أخرى :)). وبالتالي يمكن التعبير عن كل هذا على النحو التالي: هناك كنيسة ستخبر رعيتها بشيء يمكنك التسجيل فيه أو على العكس من ذلك تركه:
public interface Church {
    void registerParishioner(Parishioner parishioner);
    void removeParishioner(Parishioner parishioner);
    void notifyParishioners();
}
هناك كنيسة كاثوليكية محددة تطبق هذه الأساليب، بالإضافة إلى الأخبار وقائمة الأشخاص الذين يجب أن تبث لهم هذه الأخبار:
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);
    }
}
هناك أحد أبناء الرعية يمكنه الدخول إلى الكنيسة أو الخروج منها (لتبسيط الكود، سنسمح له بالدخول فقط :)
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);
    }
}
وبناءً على ذلك، سيتم العمل بهذه الطريقة:
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 года");
    }
}
و نتيجة البرنامج:
Мартин Лютер узнал новость: Инквизиция была ошибкой... месса Mea Culpa 12 марта 2000 года
Жан Кальвин узнал новость: Инквизиция была ошибкой... месса Mea Culpa 12 марта 2000 года
أولئك. وبمجرد ظهور الأخبار في الكنيسة، سيتم إخطار كل من هو في مجموعة الأعضاء المسجلين في هذه الكنيسة بذلك. ما هي عيوب هذا التنفيذ: 1. أولاً، الواجهة التي يمكنك من خلالها التسجيل وتلقي الأخبار قد لا تتعلق بهذه الكنيسة فقط (قد يكون هذا مطلوبًا). ولذلك، سيكون من الممكن نقل هذا على الفور إلى واجهة منفصلة يمكن ملاحظتها. 2. يمكن فعل الشيء نفسه مع أبناء الرعية، أي نقل طريقة التحديث إلى واجهة منفصلة وتنفيذها لأبناء الرعية المطلوب. بعد ذلك، سيكون من الممكن استخدام هذه الطريقة بشكل عام ليس من قبل أبناء رعية الكنيسة الكاثوليكية، ولكن، على سبيل المثال، أولئك الذين يعيشون في وجود الجان (بمعنى حركة "الطريق إلى يونيكورن"). أولئك. إنشاء واجهة مراقب بطريقة التحديث. ماذا سيحدث في النهاية:
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);
    }
}
وهكذا: لقد "أضعفنا العلاقة" بين الكنيسة وأبناء الرعية، وهو أمر جيد بطبيعة الحال فقط في البرمجة :) الموضوع (الكنيسة الكاثوليكية) لديه فقط قائمة المستمعين (أبناء الرعية) وعند تلقي الأخبار (التغييرات)، يبث هذا الخبر لمستمعيها. الآن يمكنك إنشاء أي كيان آخر (على سبيل المثال، كنيسة بروتستانتية) وبث الأخبار إلى مستمعيك. تحتاج أيضًا إلى مراعاة أن بيانات الفئة 2 (بشكل أكثر دقة، الفئة Observable وواجهة Observer) كانت متوفرة في حزمة java.util java، ولكنها الآن مهملة مع java 9 (https://docs.Oracle. com/en/Java/javase/15/docs/api/Java.base/java/util/Observable.html): مهمل. لقد تم إهمال هذه الفئة وواجهة المراقب. نموذج الحدث الذي يدعمه Observer وObservable محدود للغاية، وترتيب الإشعارات التي يتم تسليمها بواسطة Observable غير محدد، وتغييرات الحالة ليست في مراسلات فردية مع الإشعارات. للحصول على نموذج حدث أكثر ثراءً، فكر في استخدام الحزمة java.beans. للحصول على رسائل موثوقة ومنظمة بين سلاسل الرسائل، فكر في استخدام أحد بنيات البيانات المتزامنة في الحزمة java.util.concurrent. للتعرف على برمجة نمط التدفقات التفاعلية، راجع واجهة برمجة تطبيقات التدفق. ولذلك ليست هناك حاجة لاستخدامها. ويمكنك استخدام الآخرين بدلا من ذلك، ولكن جوهر النمط لن يتغير. على سبيل المثال، دعونا نحاول استخدام PropertyChangeListener (حتى لا نكتب فئات إضافية مكتوبة بالفعل) من الحزمة java.beans. دعونا نرى كيف سيكون: فئة الموضوع:
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;
    }
}
و فئة المستمعين :
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);
    }
}
إذا قمنا بتنفيذ الكود التالي:
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 год");
}
نحصل على النتيجة التالية:
علم مارتن لوثر بالخبر: مريم العذراء هي من الحبل بلا دنس... الثور Ineffabilis Deus... 8 ديسمبر 1854 علم البابا بيوس التاسع جون كالفين الأخبار: مريم العذراء هي من الحبل بلا دنس... الثور Ineffabilis Deus ... 8 ديسمبر 1854 علم البابا بيوس التاسع مارتن لوثر بالخبر: البابا معصوم من الخطأ... ليس دائمًا بالطبع، ولكن فقط عندما يبث تعاليم الكنيسة خارج الكاتدرا... المجمع الفاتيكاني الأول 1869 علم جون كالفين الخبر: البابا معصوم من الخطأ... ليس دائماً بالطبع، ولكن فقط عندما يذيع تعاليم الكنيسة خارج الكاتدرا... المجمع الفاتيكاني الأول 1869
تعليقات
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION