65.9K
CodeProject 正在变化。 阅读更多。
Home

Java 中的观察者设计模式

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.88/5 (11投票s)

2013 年 3 月 22 日

CPOL

5分钟阅读

viewsIcon

69030

downloadIcon

8

它提供了详细的观察者设计模式和示例,并解释了 Java Ap。

顾名思义,它用于观察某些对象。观察者会监视主题(subject)的状态或属性的任何变化。假设你对某个特定对象感兴趣,并希望在其状态更改时收到通知,那么你就会观察该对象,当该对象发生任何状态或属性更改时,它就会通知你。

根据 GoF 的描述

"定义对象之间的一对多依赖关系,以便当一个对象的状态发生改变时,所有依赖者都会自动得到通知并更新"。

你可以从两个方面来理解观察者设计模式

  • 主题-观察者关系:被观察的对象称为主题(Subject),而观察主题的类称为观察者(Observer)。
  • 发布者-订阅者关系:发布者是发布数据并将其通知给已订阅该发布者的订阅者列表的人。一个简单的例子是报纸。每当发布者出版新一期报纸时,都会分发给已订阅该发布者的订阅者。

观察者不会一直监视主题的状态是否发生变化,因为它们会在主题的每一次状态变化时收到通知,直到它们停止观察主题为止。所以它遵循好莱坞原则——“不要给我们打电话,我们会给你打电话”(Don't call us, we will call you)。

一些现实生活中的例子

你可能浏览过“Flipkart.com-在线巨头”。当你在搜索某个产品但它不可用时,有一个“有货时通知我”的选项。如果你订阅了这个选项,那么当产品状态改变(即它有货时),你就会收到通知邮件“产品已到货,您可以立即购买”。在这种情况下,产品是主题,你是观察者。

假设你的永久地址发生了变化,你需要通知护照局和身份证局。那么这里的护照局和身份证局是观察者,而你是主题。

在 Facebook 上也是如此,如果你关注某人,那么每当有新动态时,你都会收到通知。

何时使用

  • 当一个对象改变其状态时,所有其他依赖对象也必须自动改变其状态以保持一致性。
  • 当主题不知道它有多少观察者时。
  • 当一个对象应该能够在不知道其他对象是谁的情况下通知其他对象时。

 观察者设计模式的 UML 图

Components

主题

  • 知道它的观察者
  • 拥有任意数量的观察者
  • 提供一个接口,用于在运行时附加和分离观察者对象

观察者

  • 提供一个更新接口,用于接收来自主题的信号

具体主题

  • 存储具体观察者对象感兴趣的状态。
  • 向其观察者发送通知

具体观察者

  • 维护对具体主题对象的引用
  • 保持观察者状态与主题一致。
  • 实现更新操作

Java 内置的观察者模式 API

Java API 提供了一个类和一个接口来实现观察者模式。

1. java.util.Observable-类

2. java.util.Observer-接口

java.util.Observable

为了被观察,类必须扩展此类。子类成为可观察的,并覆盖 java.util.Observable 的方法,其他对象可以“观察”该对象状态的变化。

方法

addObserver(Observer o) :将观察者添加到此主题的观察者列表中。

deleteObserver(Observer o) :从观察者列表中删除观察者。

notifyObservers() :如果对象已更改,则通知所有观察者。

hasChanged() :如果对象已更改,则返回 true。

setChanged() :此方法将对象标记为已更改。

clearChanged() :此方法将指示主题没有更改,或已通知所有观察者。

java.util.Observer

执行“观察”操作的类必须实现 java.util.Observer 接口。有一个单一的方法:

public void update(Observable obj, Object arg) :每当被观察对象更改时,都会调用此方法。应用程序调用 Observable 对象的 notifyObservers 方法来通知所有观察者变化。

示例

你可能浏览过“Flipkart.com-在线巨头”。当你在搜索某个产品但它不可用时,有一个“有货时通知我”的选项。如果你订阅了这个选项,那么当产品状态改变(即它有货时),你就会收到通知邮件“产品已到货,您可以立即购买”。

Java 代码

下面的接口是我们的主题接口。它包含添加或删除观察者的方法,以及在状态改变时通知所有观察者的方法。

1.Subject.java

package org.arpit.javapostsforlearning;

public interface Subject {
     public void registerObserver(Observer observer);
     public void removeObserver(Observer observer);
     public void notifyObservers();
}

下面的类是我们的具体主题类。它实现了主题接口,从而提供了上述所有三个方法的实现。

2.Product.java

package org.arpit.javapostsforlearning;

import java.util.ArrayList;

public class Product implements Subject{

	private ArrayList<Observer> observers = new ArrayList<Observer>();
    private String productName;
    private String productType;
    String availability;
    
    
	public Product(String productName, String productType,String availability) {
		super();
		this.productName = productName;
		this.productType = productType;
		this.availability=availability;
	}
	
	public ArrayList<Observer> getObservers() {
		return observers;
	}
	public void setObservers(ArrayList<Observer> observers) {
		this.observers = observers;
	}
	public String getProductName() {
		return productName;
	}
	public void setProductName(String productName) {
		this.productName = productName;
	}
	public String getProductType() {
		return productType;
	}
	public void setProductType(String productType) {
		this.productType = productType;
	}
	
	public String getAvailability() {
		return availability;
	}

	public void setAvailability(String availability) {
		this.availability = availability;
		notifyObservers();
	}

	public void notifyObservers() {
		System.out.println("Notifying to all the subscribers when product became available");
		 for (Observer ob : observers) {
             ob.update(this.availability );
      }

	}

	public void registerObserver(Observer observer) {
		 observers.add(observer);
		
	}

	public void removeObserver(Observer observer) {
		 observers.remove(observer);
		
	}

}

 下面的接口是我们的观察者接口。它包含一个名为“update”的单一方法。

3.Observer.java

package org.arpit.javapostsforlearning;
public interface Observer {
	  public void update(String availability);
}

下面的类是我们的具体观察者类。它实现了观察者接口,并为 update 方法和其他具体观察者特定方法提供实现。

4.Person.java

package org.arpit.javapostsforlearning;
public class Person implements Observer{

	String personName;

	public Person(String personName) {
		this.personName = personName;
	}

	public String getPersonName() {
		return personName;
	}

	public void setPersonName(String personName) {
		this.personName = personName;
	}

	public void update(String availabiliy) {
		
		System.out.println("Hello "+personName+", Product is now "+availabiliy+" on flipkart");
	}
}

5.ObserverPatternMain.java

package org.arpit.javapostsforlearning;
public class ObserverPatternMain {

    /**
     * @Author arpit mandliya
     */
    public static void main(String[] args) {
        Person arpitPerson=new Person("Arpit");
        Person johnPerson=new Person("John");
        
        Product samsungMobile=new Product("Samsung", "Mobile", "Not available");
        
        //When you opt for option "Notify me when product is available".Below registerObserver method
        //get executed        
        samsungMobile.registerObserver(arpitPerson);
        samsungMobile.registerObserver(johnPerson);
        
        //Now product is available
        samsungMobile.setAvailability("Available");
        
    }
}

运行它:

Notifying to all the subscribers when product became available
Hello Arpit, Product is now Available on flipkart
Hello John, Product is now Available on flipkart

在上面的程序中,当三星手机的可用性发生变化时,它会通知已订阅它的订阅者。

使用 Java 内置 API

1.Product.java

package org.arpit.javapostsforlearning;
import java.util.ArrayList;
import java.util.Observable;
import java.util.Observer;

public class Product extends Observable{
 
   private ArrayList<Observer> observers = new ArrayList<Observer>();
    private String productName;
    private String productType;
    String availability;
    
    
	public Product(String productName, String productType,String availability) {
		super();
		this.productName = productName;
		this.productType = productType;
		this.availability=availability;
	}
	
	public ArrayList<Observer> getObservers() {
		return observers;
	}
	public void setObservers(ArrayList<Observer> observers) {
		this.observers = observers;
	}
	public String getProductName() {
		return productName;
	}
	public void setProductName(String productName) {
		this.productName = productName;
	}
	public String getProductType() {
		return productType;
	}
	public void setProductType(String productType) {
		this.productType = productType;
	}
	
	public String getAvailability() {
		return availability;
	}

	public void setAvailability(String availability) {
		if(!(this.availability.equalsIgnoreCase(availability)))
		{
			this.availability = availability;
			setChanged();
			notifyObservers(this,availability);
		}
	}

	public void notifyObservers(Observable observable,String availability) {
		System.out.println("Notifying to all the subscribers when product became available");
		 for (Observer ob : observers) {
             ob.update(observable,this.availability);
      }

	}

	public void registerObserver(Observer observer) {
		 observers.add(observer);
		
	}

	public void removeObserver(Observer observer) {
		 observers.remove(observer);
		
	}
}

 

2.Person.java

package org.arpit.javapostsforlearning;
import java.util.Observable;
import java.util.Observer;

public class Person implements Observer{

	String personName;
	
	
	public Person(String personName) {
		this.personName = personName;
	}


	public String getPersonName() {
		return personName;
	}


	public void setPersonName(String personName) {
		this.personName = personName;
	}

	public void update(Observable arg0, Object arg1) {
		System.out.println("Hello "+personName+", Product is now "+arg1+" on flipkart");
		
	}

}

3.ObserverPatternMain.java

package org.arpit.javapostsforlearning;
public class ObserverPatternMain {

    /**
     * @Author arpit mandliya
     */
    public static void main(String[] args) {
        Person arpitPerson=new Person("Arpit");
        Person johnPerson=new Person("John");
        
        Product samsungMobile=new Product("Samsung", "Mobile", "Not available");
        
        //When you opt for option "Notify me when product is available".Below registerObserver method
        //get executed    
        samsungMobile.registerObserver(arpitPerson);
        samsungMobile.registerObserver(johnPerson);
        
        //Now product is available
        samsungMobile.setAvailability("Available");
         
    }
}

运行它:

Notifying to all the subscribers when product became available 
Hello Arpit, Product is now Available on flipkart
Hello John, Product is now Available on flipkart

关于观察者模式的一些要点

  • 主题和观察者之间的松耦合:主题唯一知道的就是观察者实现了 Observer 接口。你可以注册或删除任何观察者而不影响主题。
  • 支持广播通信:主题状态更改的通知不需要指定接收者。此通知会广播到所有订阅了它的感兴趣的对象。
  • 此模式的一个问题是,如果有大量订阅者,调试会变得非常困难,因为主题和观察者之间的控制流是隐含的。
  • 虚假更新:如果状态更改的标准未明确定义,有时会导致虚假更新。
© . All rights reserved.