JavaRush /Java 博客 /Random-ZH /观察者模板

观察者模板

已在 Random-ZH 群组中发布
正如四人帮所写(参考 4 位顶尖开发人员所著的《面向对象设计模式》一书),该模式的目的是定义对象之间的一对多依赖关系,当一个对象的状态发生变化,所有依赖它的对象都会收到通知并自动更新。 这种模式也称为:Dependents(下属)或Publish-Subscribe(发布者-订阅者)。但让我们尝试用天主教会的例子来弄清楚:)它有相信这个教会教义的追随者。当任何新的教条(强制性信条)和更多出现时,这些人应该知道它们。 但是如何使用这种模式用编程语言来描述呢? 1.我们有“教会之声”(教会本身或教皇在广播ex cathedra时),即某个广播员或主体在教会中宣布新闻。2. 这个教堂有教区居民,即一些想要了解重要事件的观察员。因此,今天可能有13亿教区居民,明天可能会更多或更少。而且你只需要通知那些在这个教会的人(不需要再打扰无神论者:)。因此,所有这一切都可以表达如下:有一个教会会告诉它的羊群一些事情,你可以在其中登记,或者相反,留下它:
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. 首先,你可以注册和接收消息的接口可能不仅仅涉及这个教会(这可能是必需的)。因此,可以立即将其移至单独的 Observable 接口中。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.java)。 com/en/java/javase/15/docs/api/java.base/java/util/Observable.html): 已弃用。此类和 Observer 接口已被弃用。Observer和Observable支持的事件模型相当有限,Observable传递通知的顺序是未指定的,并且状态变化与通知不是一一对应的。对于更丰富的事件模型,请考虑使用 java.beans 包。为了在线程之间实现可靠且有序的消息传递,请考虑使用 java.util.concurrent 包中的并发数据结构之一。对于反应式流式编程,请参阅 Flow API。 因此没有必要使用它们。而且你可以用其他的来代替,但是模式的本质不会改变。例如,让我们尝试使用java.beans包中的PropertyChangeListener(以免编写不必要的已经编写的类)。 让我们看看它会是什么样子: 主题类别:
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... 1854 年 12 月 8 日 教皇庇护九世约翰·加尔文获悉消息:圣母玛利亚是圣母无染原罪...公牛 Ineffabilis Deus ... 1854 年 12 月 8 日,教皇庇护九世马丁·路德得知这一消息:教皇是绝对正确的...当然并不总是如此,但只有当他在大教堂前传播教会的教义时...第一次梵蒂冈大公会议 1869 年约翰·加尔文了解到新闻:教皇是绝对正确的……当然并不总是如此,但只有当他广播前大教堂的教义时……1869 年第一届梵蒂冈大公会议
评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION