观察者设计模式

sup*_*sad 5 java design-patterns observer-pattern

观察者设计模式中,主体通过调用update()每个观察者的操作来通知所有观察者.一种方法是这样做

void notify() {
   for (observer: observers) {
      observer.update(this);
   }
}
Run Code Online (Sandbox Code Playgroud)

但是这里的问题是每个观察者都按顺序更新,观察者的更新操作可能不会被调用,直到更新之前的所有观察者.如果有一个观察者有一个无限循环的更新,那么它之后的所有观察者将永远不会得到通知.

题:

  1. 有办法解决这个问题吗?
  2. 如果是这样,那会是一个很好的例子吗?

Ano*_*on. 20

问题是无限循环,而不是一个接一个的通知.

如果你想要同时更新内容,你需要在不同的线程上解决问题 - 在这种情况下,每个监听器都需要与其他监听器同步才能访问触发事件的对象.

抱怨一个无限循环阻止其他更新发生就像抱怨拿一个锁然后进入一个无限循环阻止其他人访问锁定对象 - 问题是无限循环,而不是锁管理器.


che*_*vim 10

经典设计模式不涉及并行和线程.您必须为N个观察者生成N个线程.不过要小心,因为他们对互动将在一个线程安全的方式来完成.


Tof*_*eer 5

你可以使用java.utils.concurrent.Executors.newFixedThreadPool(int nThreads)方法,然后调用invokeAll方法(也可以使用带有timout的方法来避免无限循环).

您可以更改循环以添加一个Callable类,它接受"observer"和"this",然后在"call"方法中调用update方法.

请查看此包以获取更多信息.

这是我所说的快速而肮脏的实现:

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class Main
{
    private Main()
    {
    }

    public static void main(final String[] argv)
    {
        final Watched       watched;
        final List<Watcher> watchers;

        watched = new Watched();
        watchers = makeWatchers(watched, 10);
        watched.notifyWatchers(9);
    }

    private static List<Watcher> makeWatchers(final Watched watched,
                                              final int     count)
    {
        final List<Watcher> watchers;

        watchers = new ArrayList<Watcher>(count);

        for(int i = 0; i < count; i++)
        {
            final Watcher watcher;

            watcher = new Watcher(i + 1);
            watched.addWatcher(watcher);
            watchers.add(watcher);
        }

        return (watchers);
    }
}

class Watched
{
    private final List<Watcher> watchers;

    {
        watchers = new ArrayList<Watcher>();
    }

    public void addWatcher(final Watcher watcher)
    {
        watchers.add(watcher);
    }

    public void notifyWatchers(final int seconds)
    {
        final List<Watcher>         currentWatchers;
        final List<WatcherCallable> callables;
        final ExecutorService       service;

        currentWatchers = new CopyOnWriteArrayList<Watcher>(watchers);
        callables       = new ArrayList<WatcherCallable>(currentWatchers.size());

        for(final Watcher watcher : currentWatchers)
        {
            final WatcherCallable callable;

            callable = new WatcherCallable(watcher);
            callables.add(callable);
        }

        service = Executors.newFixedThreadPool(callables.size());

        try
        {
            final boolean value;

            service.invokeAll(callables, seconds, TimeUnit.SECONDS);
            value = service.awaitTermination(seconds, TimeUnit.SECONDS);
            System.out.println("done: " + value);
        }
        catch (InterruptedException ex)
        {
        }

        service.shutdown();
        System.out.println("leaving");
    }

    private class WatcherCallable
        implements Callable<Void>
    {
        private final Watcher watcher;

        WatcherCallable(final Watcher w)
        {
            watcher = w;
        }

        public Void call()
        {
            watcher.update(Watched.this);
            return (null);
        }
    }
}

class Watcher
{
    private final int value;

    Watcher(final int val)
    {
        value = val;
    }

    public void update(final Watched watched)
    {
        try
        {
            Thread.sleep(value * 1000);
        }
        catch (InterruptedException ex)
        {
            System.out.println(value + "interupted");
        }

        System.out.println(value + " done");
    }
}
Run Code Online (Sandbox Code Playgroud)