# Java 观察者设计模式示例 > 原文: [https://javatutorial.net/java-observer-design-pattern-example](https://javatutorial.net/java-observer-design-pattern-example) **观察者模式**是一种软件设计模式,其中一个称为主题的对象维护着一个依赖于它的所有其他对象(主题)的列表。 这些依赖者称为观察者。 如果主题(所有受抚养者(观察者)的维护者)的状态发生变化,则会自动通知他们。 它通常通过方法调用来完成。 ## 何时使用观察者模式 * 通常在对象之间存在一对多关系时使用。 * 如果一个对象(另一个**相关**)修改/更改了其“行为”,则需要更新该对象。 * 当主题的观察者数量未知时。 ## 怎么运行的 通常,会有一个 Subject.java 文件,其中包含执行所有观察者的添加,删除和更新的所有方法,或者仅初始化它们,并在不同的.java 文件中执行所有方法的功能。 按照约定,还有一个 Observer.java 文件,该文件包含一个每次主题更改时都会调用的 update()方法。 之后,您必须创建实现 Subject 类或 Observer 类的.java 文件。 请注意,这取决于您的类是应实现 Subject 还是 Observer 类文件。 ![Observer design pattern](img/585385bf3232e66f9dbf2fd9e9663c1b.jpg) 观察者设计模式 ## 现实生活中的例子 想想您最喜欢的会员服务。 也许是体育馆,或者是 Netflix,或者完全不同。 在本示例中,我们将使用 Netflix,但基本上任何其他成员资格服务都可以使用。 如果 Netflix 更改了其每月会员资格的价格,而您要为此付费,则它应通知您。 实际上,它应该通知所有注册/订阅人员服务。 ## Java 观察者设计模式示例 Subject.java ```java public interface Subject { public double getCurrentPrice(); public void setNewPrice(double newPrice); public void addNewSubscriber(Observer newSuObserver); public void removeSubscriber(Observer unsubscriber); public void notifyAllSubscribers(); } ``` 在 Subject.java 中,我们将初始化将在 SubscriptionGrabber.java 文件中使用的方法,我将在稍后向您介绍。 这些方法处理添加,删除以及主题状态更改时触发的消息。 Observer.java ```java public interface Observer { public void update(double price); } ``` 这是我们的 Observer 类。 它具有将在类 SubscriptionObserver.java 文件中创建的 update(double price)方法。 请**注意**:每次订阅价格更改时,都会调用此方法。 SubscriptionGrabber.java ```java import java.util.*; public class SubscriptionGrabber implements Subject { private List subscribers = new ArrayList(); private double price; public SubscriptionGrabber() { subscribers = new ArrayList(); } public double getCurrentPrice() { return price; } public void setNewPrice(double newPrice) { this.price = newPrice; notifyAllSubscribers(); } public void addNewSubscriber(Observer newSubscriber) { subscribers.add(newSubscriber); } public void removeSubscriber(Observer unsubscriber) { int indexOfUnsubscriber = subscribers.indexOf(unsubscriber); subscribers.remove(indexOfUnsubscriber); } public void notifyAllSubscribers() { for (Observer subscriber : subscribers){ subscriber.update(price); } } } ``` 此.java 文件使用 Subject 接口。 请注意,在 setNewPrice(double newPrice)方法中,我们在设置新价格后会通知用户。 重要的是,我们必须在价格变化后执行此操作,否则以后,如果其中有更多代码块,则可能会出现问题。 我们的 addSubscriber(Observer newSubscriber)和 removeSubscriber(Observer 取消订阅者)只是在观察者列表中添加人或从观察者列表中删除人。 我们需要在我们的模式中具有删除功能,因为我们的目的是仅通知订阅者,或者仅通知使用我们服务的人员。 我们无需通知不再使用我们服务的人员。 最后,此.java 文件中的 final 方法仅对每个 SINGLE 订户调用 update(double price)方法(我们仍未创建)。 SubscriptionObserver.java ```java public class SubscriptionObserver implements Observer { private double price; private Subject subscriberGrabber; private int subscriptionID; public SubscriptionObserver(Subject subscriptionGrabber) { this.subscriberGrabber = subscriptionGrabber; this.subscriptionID+=1; subscriberGrabber.addNewSubscriber(this); System.out.println("New Observer: " + this.subscriptionID); } public void update(double price) { System.out.println("Price changed from $" + this.price + " to $" + price); this.price = price; } } ``` 这是实际上(最终)具有更新功能的.java 文件。 请注意我是如何在其中放入打印语句的。 这非常重要(在 update 方法中包含打印语句),因为您需要直观地显示用户所发生的事情。 在**构造函数**方法中,该参数始终是一个空列表(您将在下一个.java 文件中看到),并且 subscriptionGrabber 将是我们的新列表,其中将包含订阅者。 在第 9 行,您可以看到我们正在添加此新订户。 ObserverPattern.java ```java public class ObserverPattern { public static void main(String[] args) { SubscriptionGrabber subscriptionGrabber = new SubscriptionGrabber(); SubscriptionObserver subscriptionObserver = new SubscriptionObserver(subscriptionGrabber); SubscriptionObserver subscriptionObserver2 = new SubscriptionObserver(subscriptionGrabber); SubscriptionObserver subscriptionObserver3 = new SubscriptionObserver(subscriptionGrabber); subscriptionGrabber.setNewPrice(5); } } ``` 在这里我们创建抓取程序(列表),然后将该列表作为参数传递给订阅观察者变量作为构造函数参数。 然后,我们将订阅的新价格设置为 5 美元。 预期结果将是通知所有用户价格确实已更改为 5 美元。 试试吧! ![Java observer pattern result 1](img/093de2437ac3b8a8bbdf8c8a642718cb.jpg) Java 观察者模式结果 1 它按预期工作。 现在,我们尝试再创建 2 个订阅,并查看消息是否会弹出 3 次(因为我们将有 3 个订阅)。 ![Java observer pattern result 2](img/cfc1bae16d0468d1510d715f1a929c61.jpg) Java 观察者模式结果 2 它确实打印了三遍。