【问题标题】:Callback/Command vs EventListener/Observer Pattern回调/命令与 EventListener/Observer 模式
【发布时间】:2012-02-15 14:25:15
【问题描述】:

我正在尝试设计一个异步框架,并想知道人们认为回调模式与观察者模式的优缺点。

Callback pattern:

//example callback
public interface Callback{
    public void notify(MethodResult result);
}

//example method
public class Worker{
  public void doAsyncWork(Callback callback){
     //do work
     callback.notify(result);
  }
}

//example observer pattern
public interface EventListener{
   public void notify(MethodResult result);

}

public class Worker{
  private EventListener listener;
  public registerEventListener(EventListener listener){
   this.listener=listener;
  }
  public void doAsyncWork(){
     //do work
     listener.notify(result);
  }
}

我正在使用一个似乎同时使用这两种模式的框架。 EventListener 模式不是典型的模式,因为它没有侦听器列表。这可以很容易地通过创建一个 CompositeListener 来实现,它在侦听器的优先级上有自己的语义以及如何处理事件到每个侦听器的分配,例如为每个侦听器与串行通知生成一个新线程。 (我实际上认为这是一个好主意,因为它很好地分离了关注点,并且是对标准观察者/听众模式的改进)。

你有什么想法应该在什么时候使用它们吗?

谢谢。

【问题讨论】:

  • 为了简化回调,我建议您使用一流的函数。所以它只是public void doAsyncWork(Function callback)
  • 我对这两种设计模式都很陌生,我对您的代码示例感到非常困惑。你确定这些是这两种模式的正确演示,尤其是观察者模式吗?对我来说,你写它们的方式没有区别。不过不要误会我的意思。我真诚地感谢你的问题,因为我有同样的想法。只是想直截了当。谢谢!

标签: design-patterns asynchronous callback observer-pattern command-pattern


【解决方案1】:

命令、回调和观察者模式具有不同的语义:

  • 回调 - 通知单个调用者某些操作已完成并产生某些结果
  • 观察者 - 通知零到 n 个相关方发生了某些事件(例如完成的操作)
  • command - 将操作调用封装在对象中,从而使其可通过线路传输或持久化

在您的示例中,您可以结合回调和观察者模式来实现更大的 API 灵活性:

  1. 使用回调模式触发操作,并异步通知调用者触发的操作已完成。
  2. 使用 event/observer 模式让其他一些组件(触发操作)有机会在操作完成时收到通知。

【讨论】:

  • 这里的关键点是: - 使用回调通知触发者 - 使用触发事件通知观察者,在这种情况下,不会触发事件。
  • 三种模式之间差异的解释对我有帮助。
【解决方案2】:

这两种模式都很棒,选择哪一种取决于您要构建什么以及如何使用您的框架。

如果您正在尝试构建某种具有以下典型工作流程的发布-订阅系统:

  • 客户端启动异步任务并忘记它
  • 多个处理程序在任务完成时收到通知

那么Observer 模式是您的自然选择。当你在做一个框架时,你还应该考虑使用EventBus 模式来实现松耦合。

如果您只需要一个简单的异步执行并且使用您的框架的典型流程是:

  • 启动异步任务
  • 完成后做某事

  • 启动异步任务
  • 做点什么
  • 等到完成后再做点什么

那么你应该使用简单的Callback

但为了获得更可用和更干净的 API,我建议您摆脱 Callback 抽象并设计您的工作代码以返回某种 Future

public interface Worker<T> {

    Future<T> doAsync();

}

Worker可以通过以下方式使用:

Future<Integer> future = worker.doAsync();

// some work here

Integer result = future.get(); // waits till async work is done

Future 可以是标准的java Future。但我建议你使用 guava 库中的ListenableFuture

【讨论】:

    【解决方案3】:

    我认为回调模式更好,因为它更简单,这意味着它更容易预测,并且由于它自己的变异状态而不太可能出现错误。 the way GWT handles browser / server communication 就是一个例子。

    您可能想使用泛型:

    //example callback
    public interface Callback<T> {
        public void notify(T result);
    }
    
    //example method
    public class Worker{
      public void doAsyncWork(Callback<SomeTypeOrOther> callback){
         //do work
         callback.notify(result);
      }
    }
    

    【讨论】:

      【解决方案4】:

      让我们以 Lamp 和 Switch 为例,看看观察者模式和命令模式之间的区别。

      观察者模式

      • Switch 是 Subject 并且灯列表是 Observers,在其上打开/关闭 可以应用操作。
      • 这是一对多的关系。
      • 动作 ON/OFF 实际上是最简单形式的函数。
      • 不提供最简单形式的命令封装。

      命令模式

      • 另一方面,在命令模式中,Actions ON/OFF 变为 Command 类。

      • Command 类包含可以对其应用操作的接收器 Lamp。

      • 命令模式通常提供一对一的关系,但也可以 也可以缩放以提供一对多。

      • 命令模式为命令提供适当的封装。

      【讨论】:

        【解决方案5】:

        这两种模式几乎没有共同的意图,除了,

        可观察模式可以通知多个侦听器。另一方面,命令模式最适合您需要单个回调处理程序的情况。

        在命令模式中,很容易实现撤消操作。

        干杯!

        【讨论】:

          【解决方案6】:
          • 回调:作为参数传递给函数的可执行代码,当特定事件发生时调用该函数。它可以在不同的编程语言中以不同的形式实现,例如函数指针、匿名函数和监听器/观察器(面向对象范式)。它通常指的是单个可执行代码,但这不是必需的。反例:Android SDK(API 级别 29)中的 SurfaceHolder 接口允许使用 addCallback() 方法注册多个回调。
          • 侦听器/观察者:在面向对象的范式中,它是一个具有方法的对象,该方法作为参数传递给在特定事件发生时调用的函数。这是多个回调的一种可能实现。
          • 观察者模式:一种面向对象的软件设计模式,它建议使用观察者/侦听器来将观察者类与被观察类分离。

          在您的具体代码中,Callback 和 EventListener 之间的唯一区别是:

          • 您只允许注册一个回调,但允许注册多个事件监听器
          • 回调注册与异步任务的执行同步,EventListener注册不同步。

          前者更简单,后者更灵活。如果您正在创建一个可重用的框架,则后者更有意义。

          Command 设计模式是在对象中执行操作所需的所有信息的封装,它与用于通知事件的机制无关。

          【讨论】:

            猜你喜欢
            • 2011-02-20
            • 2015-01-19
            • 1970-01-01
            • 2010-12-02
            • 2010-11-12
            • 2017-05-10
            • 2017-01-08
            • 2011-06-28
            • 2016-12-16
            相关资源
            最近更新 更多