2

在观察者设计模式中,观察者观察主题和/或可观察对象。观察者收到他们的更新通知。

我很困惑这两个东西(主题和可观察的)是否本质上是相同的东西?还是两者之间有细微的差别?

4

4 回答 4

6

只要一个或多个观察者必须观察一个主题,就可以使用观察者设计模式。

Observable - 定义将观察者附加和解除附加到客户端的操作的接口或抽象类。在 GOF 书中,这个类/接口被称为Subject

它们本质上是相同的。

于 2015-10-01T05:04:24.457 回答
2

是的,两者都是一样的。

观察者可以观察到对象。Subject 保存了一个观察者列表,以便它可以通知这些观察者任何状态变化。

检查下面的 Python 代码,取自Wikipedia

class Observable:
    def __init__(self):
        self.__observers = []

    def register_observer(self, observer):
        self.__observers.append(observer)

    def notify_observers(self, *args, **kwargs):
        for observer in self.__observers:
            observer.notify(self, *args, **kwargs)


class Observer:
    def __init__(self, observable):
        observable.register_observer(self)

    def notify(self, observable, *args, **kwargs):
        print('Got', args, kwargs, 'From', observable)


subject = Observable()
observer = Observer(subject)
subject.notify_observers('test')

在此处输入图像描述

于 2015-10-01T04:56:04.393 回答
1

主体和观察者是两个不同的实体(对象):

但是关于你的问题,

观察者观察主体或可观察物

可以观察到主题的另一个名称,因此它们是相同的

Subject 维护着一个观察者列表,所有观察者都在 Subject 上注册。因此,每当主题发生某些事件时,他都会通知所有观察者。

例子:

假设您有一个名为 HTTPEngine 的类,它处理所有与 HTTP 相关的内容(连接、数据检索等)。

为了使 HTTPEngine 可以跨不同对象重用,它维护了一个说 IHTTPObserver 的列表。

因此,任何希望使用 HTTPEngine 的对象,实现接口 HTTPObserver,在 HTTPEngine 注册,然后收到事件通知。

前任:

class HTTPObserver
{
 public:
 virtual void onEvent() = 0;

}

因此,假设一个名为“client”的类想要使用 HTTPENgine。

class client: public HTTPObserver
{
  void onEvent(){//got the event notification}
}

现在,HTTPENgine 维护了一个观察者列表:

class HTTPEngine
{
private:
 vector<IHTTPObserver*> clients;
public:
 void register(IHTTPObserver* client){clients.push_back(client);} 
 void notifyclients(){
 for(it=vector.begin();it!=Vector.end();it++)
 (*it)->notifyEvent();}

};
于 2015-10-01T04:55:53.763 回答
0

当使用一对多关系时使用观察者设计模式,如果更新主对象,则更新依赖对象。观察者模式是行为设计​​模式的一个示例。它具有三个参与者,例如主类、依赖超类和子类。

查看以下观察者设计模式的 UML 图。

在此处输入图像描述

  1. Circle类是主类。它有一个特殊的属性observers,可以让所有的观察者保持在圈子里。它可以附加(或在需要时重新附加)观察者。
  2. 该类Observer是依赖的超类。它是一个抽象类,为类提供通用方法Circle
  3. 子观察者类 (AreaObserverPerimeterObserver) 是主类 ( Circle)的依赖项
  4. 我曾经ObserverExample测试过这个例子。它不是观察者设计模式的内容。

Circle.java

public class Circle {

    private List<Observer> observers;
    private double radius;

    public Circle() {
        observers = new ArrayList<>();
    }

    public double getRadius() {
        return radius;
    }

    public void setRadius(double radius) {
        this.radius = radius;
        notifyObservers();
    }

    /**
     * attach an observer to the circle
     */
    public void attach(Observer observer) {
        observers.add(observer);
    }

    /**
     * notify all observers on update
     */
    public void notifyObservers() {
        for (Observer observer : observers) {
            observer.update();
        }
    }
}

观察者.java

public abstract class Observer {

    protected Circle circle;

    public Observer(Circle circle) {
        this.circle = circle;
    }

    public abstract void update();
}

AreaObserver.java

public class AreaObserver extends Observer {

    public AreaObserver(Circle circle) {
        super(circle);
    }

    @Override
    public void update() {
        System.out.printf("New area is: %f\n", Math.PI * circle.getRadius() * circle.getRadius());
    }
}

PerimeterObserver.java

public class PerimeterObserver extends Observer {

    public PerimeterObserver(Circle circle) {
        super(circle);
    }

    @Override
    public void update() {
        System.out.printf("New Perimeter is: %f\n", 2 * Math.PI * circle.getRadius());
    }
}

ObserverExample.java

public class ObserverExample {

    public static void main(String[] args) {
        Circle circle = new Circle();

        PerimeterObserver perimeterObserver = new PerimeterObserver(circle);
        circle.attach(perimeterObserver);

        AreaObserver areaObserver = new AreaObserver(circle);
        circle.attach(areaObserver);

        System.out.println("Set radius: 7.0");
        System.out.println("---------------");
        circle.setRadius(7.0);

        System.out.println();

        System.out.println("Set radius: 5.0");
        System.out.println("---------------");
        circle.setRadius(5.0);
    }
}

输出:

Set radius: 7.0
---------------
New Perimeter is: 43.982297
New area is: 153.938040

Set radius: 5.0
---------------
New Perimeter is: 31.415927
New area is: 78.539816

根据输出,更新主类时似乎所有观察者都更新了。

于 2015-10-01T06:03:13.243 回答