观察者设计模式 -- java 领域 和 design-patterns 领域 和 observer-pattern 领域 相关 的问题

Observer Design Pattern


简体版||繁體版
5
vote

问题

中文

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

  docker-compose down0  

但是这里的问题是每个观察者在序列中更新,并且在更新之前,可能不会调用观察者的Observer的更新操作。如果有一个具有无限循环的观察者,则将永远不会通知所有观察者。

问题:

  1. 有没有办法解决这个问题?
  2. 如果是这样,那么一个很好的例子是什么?
英文原文

In the Observer Design Pattern, the subject notifies all observers by calling the update() operation of each observer. One way of doing this is

void notify() {    for (observer: observers) {       observer.update(this);    } } 

But the problem here is each observer is updated in a sequence and update operation for an observer might not be called till all the observers before it is updated. If there is an observer that has an infinite loop for update then all the observer after it will never be notified.

Question:

  1. Is there a way to get around this problem?
  2. If so what would be a good example?
</div
        

回答列表

10
 
vote
vote
最佳答案
 

经典设计模式不涉及并行和穿线。您必须为N观察员产生n个线程。虽然它们对的互动以来,但这将必须以线程安全的方式完成。

 

Classic design patterns do not involve parallelism and threading. You'd have to spawn N threads for the N observers. Be careful though since their interaction to this will have to be done in a thread safe manner.

</div
 
 
20
 
vote

问题是无限循环,而不是其他通知。

如果您希望同时要更新,您需要在不同的线程上射击 - 在这种情况下,每个侦听器都需要与其他侦听器同步,以便访问触发事件的对象。

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

 

The problem is the infinite loop, not the one-after-the-other notifications.

If you wanted things to update concurrently, you'd need to fire things off on different threads - in which case, each listener would need to synchronize with the others in order to access the object that fired the event.

Complaining about one infinite loop stopping other updates from happening is like complaining that taking a lock and then going into an infinite loop stops others from accessing the locked object - the problem is the infinite loop, not the lock manager.

</div
 
 
   
   
5
 
vote

您可以使用java.utils.concurrent.executors.newfixedThreadPool(int nthreads)方法,然后调用InvokeAll方法(可以使用Timout使用The One以避免无限循环)。

您会更改循环以添加可调用的类,该类拍摄"观察者" 和"此" ,然后在"呼叫" 方法中调用更新方法。

看看这个包以获取更多信息。

这是我在谈论的快速和肮脏的实现:

  /**  * Resize the given bitmap to the given width/height by the given option.<br>  */  enum RequestSizeOptions {     RESIZE_FIT,     RESIZE_INSIDE,     RESIZE_EXACT }  static Bitmap resizeBitmap(Bitmap bitmap, int reqWidth, int reqHeight, RequestSizeOptions options) {     try {         if (reqWidth > 0 && reqHeight > 0 && (options == RequestSizeOptions.RESIZE_FIT ||                 options == RequestSizeOptions.RESIZE_INSIDE ||                 options == RequestSizeOptions.RESIZE_EXACT)) {              Bitmap resized = null;             if (options == RequestSizeOptions.RESIZE_EXACT) {                 resized = Bitmap.createScaledBitmap(bitmap, reqWidth, reqHeight, false);             } else {                 int width = bitmap.getWidth();                 int height = bitmap.getHeight();                 float scale = Math.max(width / (float) reqWidth, height / (float) reqHeight);                 if (scale > 1 || options == RequestSizeOptions.RESIZE_FIT) {                     resized = Bitmap.createScaledBitmap(bitmap, (int) (width / scale), (int) (height / scale), false);                 }             }             if (resized != null) {                 if (resized != bitmap) {                     bitmap.recycle();                 }                 return resized;             }         }     } catch (Exception e) {         Log.w("AIC", "Failed to resize cropped image, return bitmap before resize", e);     }     return bitmap; } 1  
 

You could make use of the java.utils.concurrent.Executors.newFixedThreadPool(int nThreads) method, then call the invokeAll method (could make use of the one with the timout too to avoid the infinite loop).

You would change your loop to add a class that is Callable that takes the "observer" and the "this" and then call the update method in the "call" method.

Take a look at this package for more info.

This is a quick and dirty implementation of what I was talking about:

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");     } } 
</div
 
 
3
 
vote

我会更关心观察者抛出异常而不是无限期地循环。您目前的实施不会在这样的事件中通知剩余的观察员。

 

I'd be more concerned about the observer throwing an exception than about it looping indefinitely. Your current implementation would not notify the remaining observers in such an event.

</div
 
 
2
 
vote

1。有没有办法解决这个问题?

是,确保观察者工作正常并及时返回。

2。有人可以用一个例子来解释它。

确定:

  class ObserverImpl implements Observer {      public void update( Object state ) {             // remove the infinite loop.             //while( true ) {             //   doSomething();             //}              // and use some kind of control:             int iterationControl = 100;             int currentIteration = 0;             while( curentIteration++ < iterationControl ) {                  doSomething();             }      }      private void doSomething(){} }   

这一个防止给定的循环去流动(如果它有意义,它应该最多100次运行)

其他机制是在第二个线程中启动新任务,但如果它进入无限循环,则最终会消耗所有系统内存:

  class ObserverImpl implements Observer {      public void update( Object state ) {          new Thread( new Runnable(){               public void run() {                  while( true ) {                      doSomething();                  }              }           }).start();      }      private void doSomething(){} }   

将使观察者实例立即返回,但它只是一个幻觉,你必须实际做的是避免无限循环。

最后,如果您的观察员工作正常,但您只想迟早通知它们,您可以看一下此相关问题:在执行所有鼠标事件侦听器后调用代码。。

 

1. Is there a way to get around this problem?

Yes, make sure the observer work fine and return in a timely fashion.

2. Can someone please explain it with an example.

Sure:

class ObserverImpl implements Observer {      public void update( Object state ) {             // remove the infinite loop.             //while( true ) {             //   doSomething();             //}              // and use some kind of control:             int iterationControl = 100;             int currentIteration = 0;             while( curentIteration++ < iterationControl ) {                  doSomething();             }      }      private void doSomething(){} } 

This one prevent from a given loop to go infinite ( if it makes sense, it should run at most 100 times )

Other mechanism is to start the new task in a second thread, but if it goes into an infinite loop it will eventually consume all the system memory:

class ObserverImpl implements Observer {      public void update( Object state ) {          new Thread( new Runnable(){               public void run() {                  while( true ) {                      doSomething();                  }              }           }).start();      }      private void doSomething(){} } 

That will make the that observer instance to return immediately, but it will be only an illusion, what you have to actually do is to avoid the infinite loop.

Finally, if your observers work fine but you just want to notify them all sooner, you can take a look at this related question: Invoke a code after all mouse event listeners are executed..

</div
 
 
0
 
vote

所有观察员都收到通知,这就是你得到的所有保证。

如果要实现一些花哨的顺序,可以执行以下操作:

  • 连接单个观察者;
  • 让这个主要观察者以您在代码中或其他一些方式定义的顺序通知他的朋友。

将您远离经典的观察者模式,因为您的听众是硬连线的,但如果它是你需要的......做到!

 

All observers get notified, that's all the guarantee you get.

If you want to implement some fancy ordering, you can do that:

  • Connect just a single Observer;
  • have this primary Observer notify his friends in an order you define in code or by some other means.

That takes you away from the classic Observer pattern in that your listeners are hardwired, but if it's what you need... do it!

</div
 
 
0
 
vote

如果您有一个带有"无限循环" 的观察者,则它不再是观察者模式。

您可以向每个观察者发射不同的线程,但必须禁止观察者在观察到的对象上改变状态。

最简单(和最愚蠢的)方法只是拍摄你的榜样并使其线程。

  void notify() {    for (observer: observers) {       new Thread(){           public static void run() {               observer.update(this);           }        }.start();    } }   

(这是用手编码的,是未经测试的,可能有一个错误或五 - 并且这是一个坏主意,无论如何)

这个问题是它将使您的机器块起来,因为它必须立即分配一堆新线程。

因此,要立即启动的所有胎面都解决问题,请使用ThreadPoolExecutor,因为它将是a)回收线程,b)可以限制运行的最大线程数。

这不是在您的"循环永远" 的情况下的确定性,因为每个永远的循环都将永久地从池中的其中一个线程中使用其中一个线程。

您最好的选择是不允许它们永远循环,或者如果必须,请使它们创建自己的线程。

如果您必须支持无法改变的类,但您可以识别哪个将快速运行,哪个将"永久" (在计算机条款中,我认为这相当于超过一秒或两个)然后您可以使用像这样的循环:

  void notify() {    for (observer: observers) {       if(willUpdateQuickly(observer))           observer.update(this);       else           new Thread(){               public static void run() {                   observer.update(this);               }            }.start();    } }   
嘿,如果它实际上是"永远的循环" ,它会消耗一个线程吗?它真的听起来像你可能需要花一些时间在你的设计上。
 

If you have an observer with an "infinite loop", it's no longer really the observer pattern.

You could fire a different thread to each observer, but the observers MUST be prohibited from changing the state on the observed object.

The simplest (and stupidest) method would simply be to take your example and make it threaded.

void notify() {    for (observer: observers) {       new Thread(){           public static void run() {               observer.update(this);           }        }.start();    } } 

(this was coded by hand, is untested and probably has a bug or five--and it's a bad idea anyway)

The problem with this is that it will make your machine chunky since it has to allocate a bunch of new threads at once.

So to fix the problem with all the treads starting at once, use a ThreadPoolExecutor because it will A) recycle threads, and B) can limit the max number of threads running.

This is not deterministic in your case of "Loop forever" since each forever loop will permanently eat one of the threads from your pool.

Your best bet is to not allow them to loop forever, or if they must, have them create their own thread.

If you have to support classes that can't change, but you can identify which will run quickly and which will run "Forever" (in computer terms I think that equates to more than a second or two) then you COULD use a loop like this:

void notify() {    for (observer: observers) {       if(willUpdateQuickly(observer))           observer.update(this);       else           new Thread(){               public static void run() {                   observer.update(this);               }            }.start();    } } 

Hey, if it actually "Loops forever", will it consume a thread for every notification? It really sounds like you may have to spend some more time on your design.

</div
 
 

相关问题

9  最佳发布/订阅“中间件”[已关闭]  ( Best publish subscribe middleware ) 
关闭。这个问题不符合堆栈溢出指南。它目前不接受答案。 想要改进这个问题?更新问题,所以它是关于堆栈溢出的主题。 关闭 7年前。 ...

3  如何通过观察者调用外部逻辑时保护数据结构一致性?  ( How to guard data structure consistency when calling external logic via observer ) 
我目前重构了一个应用程序,其中类可以调用观察者如果他们的状态发生变化。这意味着只要:,观察者被调用 实例中的数据类更改 类的新实例是创建 类的实例被删除 这是最后一个让我担心的案例。 假设我的班级是书。观察者存储在一个名为BookManager(BookManager还保留所有书籍的类)。这意味着我们有这个: ...

0  多个观察者和多个可观察到  ( Multiple observer and multiple observable ) 
我正在使用Java中的可观察类/观察者接口来实现观察者模式。如果我有一个物体,我希望能够观察几个其他可观察对象(多个观察到)并具有多个观察者(多个观察者) 问题在b类中不是AnobServable,但我希望在A和B中值为生成图表 public void update(Observable anObservable...

34  在JSON中传递函数并执行  ( Pass function in json and execute ) 
是有没有方法可以将函数传递为json字符串(与json.stringify转换),将其发送到另一个函数,解析JSON,然后执行json中的函数?我正在使用jQuery和JavaScript。 ...

0  Rails延迟作业访问后台工作的价值  ( Rails delayed job accessing value of background job ) 
在我的Rails应用程序中,我每秒都有一个定时器滴答,基于哪个不同的对象改变了他们的状态。因此,我决定使用观察者。但是,当我跑了观察者时,我注意到它挂断了我的整个应用程序,直到定时器完成。因此,我正在考虑使用delayed_job保持定时器作为后台作业。 现在我的查询是有没有办法从每秒获取计时器的值并将其用于控制​​...

3  iPhone MKMAPVIEW注释观察员可选一次  ( Iphone mkmapview annotations observers selectable once ) 
我在mkmapview上有不同的自定义映射注释,并且在创建自定义视图时,我添加观察者并禁用默认弹出窗口。 在MapViewController.m的顶部: static NSString* const ANNOTATION_SELECTED_DESELECTED = @"annotationSelectedOrD...

10  在Rails中,一个扫除程序没有被称为纯粹的设置  ( In rails a sweeper isnt getting called in a model only setup ) 
我正在使用Rails应用程序,在那里我正在使用页面缓存来存储静态HTML输出。缓存工作正常。但是,我在缓存中遇到了麻烦。 我相信我的问题是部分原因是因为我没有从我的控制器中到期缓存。在模型中处理此类所需的所有行动。这似乎应该是可行的,但是所有对模型的高速缓存到期的引用都是在我发现的基于模型的缓存到期似乎是超出日期,或...

4  DataBinding和BaseBserver - Android MVVM  ( Databinding and baseobserver android mvvm ) 
我有一个文本字段,它是一个像XML这样的视图模型,我希望UI更新CardView的TXTProvider字段。 我该如何向我的视图中通知更改视图? <layout xmlns:bind="http://schemas.android.com/tools"> <data> <variable name="...

6  如何触发在Magento收到的付款的活动?  ( How to trigger an event on payment received in magento ) 
问候,在magento我想触发一个事件,一旦订单已经设置为处理(通过网关确认或手动),示例:如果一般客户(ID 1)花费超过100美元并付款确认,将其组ID设置为4(Silver VIP,通过促销规则全球折扣2%) 我会给这个赏金,但我想在2天之前答案O_o 编辑:我收到的答案到目前为止只是一个部分答案,我也发现...

1  Magento:登录过程前的火灾活动  ( Magento fire event before the login process ) 
读过一些帖子后,我试图在用户登录前实施观察者以启动事件。我会解释:我有一个论坛和一个博客,使用另一个框架,我希望访问者只记录一次:博客,论坛或eShop。之后,他将被记录为其他领域。例如,我正在浏览论坛,我登录论坛。然后,当我打开商店时,我已经登录了。相同的是相反的方式。 它有效,但只是一个问题:当我登录论坛/博客...




© 2022 it.wenda123.org All Rights Reserved. 问答之家 版权所有