java8 之观察者模式

观察者模式是一种比较常见的方案,某些事件发生时(比如状态转变),如果一个对象(通 常我们称之为主题)需要自动地通知其他多个对象(称为观察者),就会采用该方案。创建图形 用户界面(GUI)程序时,你经常会使用该设计模式。这种情况下,你会在图形用户界面组件(比 如按钮)上注册一系列的观察者。如果点击按钮,观察者就会收到通知,并随即执行某个特定的 行为。 但是观察者模式并不局限于图形用户界面。比如,观察者设计模式也适用于股票交易的 情形,多个券商可能都希望对某一支股票价格(主题)的变动做出响应。


设计图

让我们写点儿代码来看看观察者模式在实际中多么有用。你需要为Twitter这样的应用设计并 实现一个定制化的通知系统。想法很简单:好几家报纸机构,比如《纽约时报》《卫报》以及《世 界报》都订阅了新闻,他们希望当接收的新闻中包含他们感兴趣的关键字时,能得到特别通知。
首先,你需要一个观察者接口,它将不同的观察者聚合在一起。它仅有一个名为notify的 方法,一旦接收到一条新的新闻,该方法就会被调用:

interface Observer { 
  void notify(String tweet); 
}

现在,你可以声明不同的观察者(比如,这里是三家不同的报纸机构),依据新闻中不同的 关键字分别定义不同的行为:

class NYTimes implements Observer{ //纽约时报
  public void notify(String tweet) { 
    if(tweet != null && tweet.contains("money")){ 
      System.out.println("Breaking news in NY! " + tweet); 
    } 
   } 
} 


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


class LeMonde implements Observer{ //世界报
  public void notify(String tweet) { 
    if(tweet != null && tweet.contains("wine")){ 
      System.out.println("Today cheese, wine and news! " + tweet); 
    } 
  } 
}

还遗漏了最重要的部分:Subject!让我们为它定义一个接口:

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

Subject使用registerObserver方法可以注册一个新的观察者,使用notifyObservers 方法通知它的观察者一个新闻的到来。让我们更进一步,实现Feed类:

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

这是一个非常直观的实现:Feed类在内部维护了一个观察者列表,一条新闻到达时,它就 进行通知。

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接口的所有实现类都提供了一个方法:notify。新闻到达时,它们都只是对同一 段代码封装执行。Lambda表达式的设计初衷就是要消除这样的僵化代码。使用Lambda表达式后, 你无需显式地实例化三个观察者对象,直接传递Lambda表达式表示需要执行的行为即可:

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

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

那么,是否我们随时随地都可以使用Lambda表达式呢?答案是否定的!我们前文介绍的例 子中,Lambda适配得很好,那是因为需要执行的动作都很简单,因此才能很方便地消除僵化代 码。但是,观察者的逻辑有可能十分复杂,它们可能还持有状态,抑或定义了多个方法,诸如此 类。在这些情形下,你还是应该继续使用类的方式。

传统观察者模式UML模型图

你可能感兴趣的:(java8 之观察者模式)