97.md 6.5 KB
Newer Older
W
wizardforcel 已提交
1
# Java 观察者设计模式示例
W
init  
wizardforcel 已提交
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24

> 原文: [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 更改了其每月会员资格的价格,而您要为此付费,则它应通知您。 实际上,它应该通知所有注册/订阅人员服务。

W
wizardforcel 已提交
25
## Java 观察者设计模式示例
W
init  
wizardforcel 已提交
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145

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<Observer> subscribers = new ArrayList<Observer>();
    private double price;

    public SubscriptionGrabber() {
        subscribers = new ArrayList<Observer>();
    }

    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

它确实打印了三遍。