观察者模式Java - 使用线程的多个观察者

4

我正在尝试学习所有主要的设计模式。我刚开始学习Java中的多线程。这是一个观察者模式代码,其中有多个观察者,可观察对象在while true循环中运行。我遇到了以下两个问题:

  1. When calling notifyObservers, I have to pass the new value to it even though my observers are accessing the getter of the observable value. If I don't, then the observer gets/prints value null. I have created a setter function to demonstrate it.
  2. I created two observers & obviously most of the code for both of them is similar. I'm not sure how to implement new observers or create a list of observers without replicating my code. I created a basicObserver & tried to inherit it in MyObserver3, but I am not sure how exactly do I implement it.

    import java.util.Observable;
    import java.util.Observer;
    
    public class ObserverPatternMultipleObserversUsingThreads
    {
        public static void main(String[] args)
        {
            ObservableValue observableObj = new ObservableValue(10);
    
            MyObserver1 observer1 = new MyObserver1(observableObj);
            MyObserver2 observer2 = new MyObserver2(observableObj);
            MyObserver3 observer3 = new MyObserver3(observableObj);
    
            observableObj.addObserver(observer1);
            observableObj.addObserver(observer2);
    
            observableObj.start();
    
            System.out.println("Calling Listeners");
    
            observer1.printObservablesValue();
            observer2.printObservablesValue();
    
            System.out.println("Main thread says: Sleeping for 3 second(s)");
    
            try
            {
                Thread.sleep(3000);
            }
    
            catch (InterruptedException e)
            {
                e.printStackTrace();
            }
    
            System.out.println("Main thread says: Going to change Observables Value");
    
            observableObj.setValue(20);
        }
    }
    
    class basicObserver
    {
        private ObservableValue obsValObj = null;
    
        public basicObserver(ObservableValue obsVal)
        {
            this.obsValObj = obsVal;
        }
    
        public void printObservablesValue()
        {
            System.out.println("Observer says: [" + obsValObj.getValue() + "]");    
        }
    
        public void update(Observable o, Object arg)
        {
            Integer count = (Integer) arg;
            System.out.println("Observer says: Value changed to: [" + count + "]");
        }
    }
    
    class MyObserver3 extends basicObserver implements Observer
    {
        public MyObserver3(ObservableValue obsVal)
        {
            super(obsVal);
        }
    }
    
    class MyObserver1 implements Observer
    {
        private ObservableValue obsValObj = null;
    
        public MyObserver1(ObservableValue obsVal)
        {
            this.obsValObj = obsVal;
        }
    
        public void printObservablesValue()
        {
            System.out.println("MyObserver1 says: [" + obsValObj.getValue() + "]"); 
        }
    
        public void update(Observable o, Object arg)
        {
            Integer count = (Integer) arg;
            System.out.println("MyObserver1 says: Value changed to: [" + count + "]");
        }
    }
    
    class MyObserver2 implements Observer
    {
        private ObservableValue obsValObj = null;
    
        public MyObserver2(ObservableValue obsVal)
        {
            this.obsValObj = obsVal;
        }
    
        public void printObservablesValue()
        {
            System.out.println("MyObserver2 says: [" + obsValObj.getValue() + "]"); 
        }
    
        public void update(Observable o, Object arg)
        {
            Integer count = (Integer) arg;
            System.out.println("MyObserver2 says: Value changed to: [" + count + "]");
        }
    }
    
    class ObservableValue extends Observable implements Runnable
    {
        private int n = 0;
    
        public ObservableValue(int x)
        {
            this.n = x;
        }
    
        public int getValue()
        {
            return n;
        }
    
        public void setValue(int x)
        {
            this.n = x;
            setChanged();
            System.out.println("ObservableValue says: setChanged() has been called");
    
    //      notifyObservers(new Integer(this.n));
            notifyObservers();                                                                  // makes the observers print null
            System.out.println("ObservableValue says: notifyObservers() has been called");
        }
    
        public void start()
        {
            new Thread(this).start();
        }
    
        public void run()
        {
            int count = -1;
            int a=0, b=0;
    
            while(a==b)
            {
                if(count != n)
                {
                    count = n;
                    System.out.println("ObservableValue says: My count is: [" + count + "]");
    
                    count++;
                    System.out.println("ObservableValue says: Now my count is: [" + count + "]");
                    setChanged();
                    System.out.println("ObservableValue says: setChanged() has been called");
    
                    notifyObservers(new Integer(count));
                    System.out.println("ObservableValue says: notifyObservers() has been called");
    
                    System.out.println("ObservableValue says: Sleeping for 5 second(s)");
    
                    try
                    {
                        Thread.sleep(5000);
                    }
    
                    catch (InterruptedException e) { e.printStackTrace(); }
                }
            }
        }
    }
    

关于这些概念的最佳实践方面,我真的很感谢您提供任何指导/建议/评论。

请帮忙。


这个教程可能很有用。请参考:http://www.java2s.com/Code/Java/Design-Pattern/AsimpledemoofObservableandObserver.htm - Sazzadur Rahaman
感谢 @SazzadurRahaman,我理解了这个概念。我的问题有点具体,即为什么即使在更改可观察对象的值后调用 setChanged() 和 notifyObservers(),我的观察者仍无法获得最新的值。 - MdT
2个回答

3
  1. 不需要将Observable实例引用传递给观察者,这实际上是一个坏主意,因为您会在update()方法中得到对Observable实例和修改后的值的引用。此外,如果您没有将观察者绑定到特定的Observable实例,则可以将它们附加到其他Observable而无需进行任何修改。

  2. 要使用多个观察者,并不一定需要多个类。在您的情况下,您可能可以通过同一类的多个实例来实现所需的功能。


谢谢 @Costi Ciudatu。我明白你的第二点了。在你的第一点中,你提到了不应该传递Observable实例。你是指notifyObservers方法对吗?这正是我的观点。我知道我不应该这样做,但如果我不这样做,我的观察者就无法获取值。为什么他们不能访问最新的值 - 这就是我试图调试的问题。 - MdT
不,我的意思是你不应该将可观察实例作为构造函数参数传递给观察者。它们在update()方法中获取所有所需信息,让它们依赖于可观察实例是一个无用的限制。 - Costi Ciudatu

2
  1. Try changing your update method to this:

    public void update(Observable o, Object arg)
    {
        if (o instanceof ObservableValue){
            ObservableValue obs = (ObservableValue) o;
            System.out.println("MyObserver1 says: Value changed to: [" + obs.getValue() + "]");
        }else{
            System.out.println("The observable object was not of the correct type");
        }
    
    }
    

这将允许您访问任何您需要的可观察对象上的方法,以便您可以获取所有可能已更改的值并相应地进行更新。

2 我没有看到你的类之间有太大的区别,你不能只创建那些观察者的新实例而不是为每个观察者都有一个完整的类吗?

我已删除我认为您不需要的类,并展示了如何使用一个观察者类来完成此操作(除非您需要为每个类提供不同的功能)。它们按照先前的编号进行排序。

import java.util.Observable;
import java.util.Observer;

public class ObserverPatternMultipleObserversUsingThreads
{
    public static void main(String[] args)
{
    ObservableValue observableObj = new ObservableValue(10);

    MyObserver observer1 = new MyObserver(observableObj);
    MyObserver observer2 = new MyObserver(observableObj);

    observableObj.addObserver(observer1);
    observableObj.addObserver(observer2);

    observableObj.start();

    System.out.println("Calling Listeners");

    observer1.printObservablesValue();
    observer2.printObservablesValue();

    System.out.println("Main thread says: Sleeping for 3 second(s)");

    try
    {
        Thread.sleep(3000);
    }

    catch (InterruptedException e)
    {
        e.printStackTrace();
    }

    System.out.println("Main thread says: Going to change Observables Value");

    observableObj.setValue(20);
    }
}


class MyObserver implements Observer
{
static int numberOfObservers = 0;
private ObservableValue obsValObj = null;
private int observerNumber;

public MyObserver(ObservableValue obsVal)
{
    numberOfObservers++;
    observerNumber = numberOfObservers;
    this.obsValObj = obsVal;
}

public void printObservablesValue()
{
    System.out.println("MyObserver"+observerNumber+" says: [" + obsValObj.getValue() + "]"); 
}

public void update(Observable o, Object arg)
{


    if (o instanceof ObservableValue){
        ObservableValue obs = (ObservableValue) o;
        System.out.println("MyObserver"+observerNumber+" says: Value changed to: [" + obs.getValue() + "]");
    }else{
        System.out.println("The observable object was not of the correct type");
    }

}
}

class ObservableValue extends Observable implements Runnable
{
    private int n = 0;

    public ObservableValue(int x)
{
    this.n = x;
}

public int getValue()
{
    return n;
}

public void setValue(int x)
{
    this.n = x;
    setChanged();
    System.out.println("ObservableValue says: setChanged() has been called");

//      notifyObservers(new Integer(this.n));
    notifyObservers();                                                                      // makes the observers print null
    System.out.println("ObservableValue says: notifyObservers() has been called");
}

public void start()
{
    new Thread(this).start();
}

public void run()
{
    int count = -1;
    int a=0, b=0;

    while(a==b)
    {
        if(count != n)
        {
            count = n;
            System.out.println("ObservableValue says: My count is: [" + count + "]");

            count++;
            System.out.println("ObservableValue says: Now my count is: [" + count + "]");
            setChanged();
            System.out.println("ObservableValue says: setChanged() has been called");

            notifyObservers(new Integer(count));
            System.out.println("ObservableValue says: notifyObservers() has been called");

            System.out.println("ObservableValue says: Sleeping for 5 second(s)");

            try
            {
                Thread.sleep(5000);
            }

            catch (InterruptedException e) { e.printStackTrace(); }
        }
    }
}
}

请原谅我的代码格式,我似乎在与stackoverflow的代码视图进行一场小战斗,正在努力修复它。 - ThePerson
谢谢@NutterzUK。我运行了你的代码,但观察者没有得到可观察对象的更新值。 - MdT
对不起,我可能有点困惑了...你说的20是什么意思呢?它对我来说是显示出来的,也许我误解了你的意思。 - ThePerson
20 是被设置为可观察对象的值。然后我在运行方法中对其进行递增,它变成了 21。观察者也应该跟随并变成 21,但它们没有。 - MdT

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接