使用Lambdas重构观察者设计模式


当某个对象(称为主体)需要在某些事件发生时(例如,状态更改)自动通知其他对象(称为观察者)的列表时,观察者设计模式是一种常见的解决方案。在使用GUI应用程序时,您通常会遇到此模式。您在GUI组件(如按钮)上注册一组观察者。如果单击该按钮,则会通知观察者并执行特定操作。但观察者模式不限于GUI。例如,观察者设计模式也适用于多个交易者(观察者)可能希望对股票(主体)的价格变化作出反应的情况。

让我们为Twitter等应用程序设计并实现自定义通知系统。这个概念很简单:几家报社(NY Times,The Guardian和Le Monde)订阅了新闻推文,如果推文包含特定关键词,可能希望收到通知。

观察者模式:不使用Lambda表达式
步骤1:创建一个Observer接口,对不同的观察者进行分组。它只有一个名为inform的方法,当有新的推文可供主题(Feed)调用时。

public interface Observer {
     void inform(String tweet);
}

第2步:让我们创建不同的观察者(这里是三份报纸),为包含在推文中的每个不同的关键词产生不同的行动。

public class NYTimes implements Observer{
 @Override
 public void inform(String tweet) {
  if(tweet != null && tweet.contains("money")){
   System.out.println(
"Breaking news in NY!" + tweet);
  }
 }
}

public class Guardian implements Observer{
 @Override
 public void inform(String tweet) {
  if(tweet != null && tweet.contains(
"queen")){
   System.out.println(
"Yet another news in London... " + tweet);
  }
 }
}

public class LeMonde implements Observer{
 @Override
 public void inform(String tweet) {
  if(tweet != null && tweet.contains(
"wine")){
   System.out.println(
"Today cheese, wine and news! " + tweet);
  }
 }
}

第3步:让我们来定义  主题  接口。

public interface Subject{
 void registerObserver(Observer o);
 void notifyObservers(String tweet);
}

第4步:这是一个非常简单的实现:feed保留一个内部观察者列表,然后它可以在推文到达时通知。

public class Feed implements Subject{
 private final List<Observer> observers = new ArrayList<>();
 public void registerObserver(Observer o) {
  this.observers.add(o);
 }
 public void notifyObservers(String tweet) {
  observers.forEach(o -> o.inform(tweet));
 }
}

第5步:我们现在可以创建一个演示应用程序来连接主题和观察者。

public static void main(String[] args) {
 Feed f = new Feed();
 f.registerObserver(new NYTimes());
 f.registerObserver(new Guardian());
 f.registerObserver(new LeMonde());
 f.notifyObservers("The queen said her favourite book is Java 8 in Action!");
}

观察者模式:使用Lambda表达式
请注意,实现Observer接口的不同类都提供了单个方法的实现:inform()
当推文到达时,它们只是包裹着一段行为,Lambda表达式专门用于删除该样板。您可以直接传递lambda表达式来表示要执行的行为,而不是显式地实例化三个观察对象:

public static void main(String[] args) {

 Feed feedLambda = new Feed();

 feedLambda.registerObserver((String tweet) -> {
  if(tweet != null && tweet.contains("money")){
   System.out.println(
"Breaking news in NY! " + tweet); }
 });
 feedLambda.registerObserver((String tweet) -> {
  if(tweet != null && tweet.contains(
"queen")){
   System.out.println(
"Yet another news in London... " + tweet); }
 });

 feedLambda.notifyObservers(
"Money money money, give me money!");

}

我们应该一直使用lambda表达式吗?答案是不!在我们描述的示例中,lambda表达式工作得很好,因为要执行的行为很简单,因此它们有助于删除样板代码。但观察者可能更复杂:他们可能有状态,定义了几种方法等。在这种情况下,你应该坚持使用类模板的样板代码。