Observer Pattern是一种经典的行为型设计模式,它定义了对象间的一种一对多(one-to-many)的依赖关系,以便当一个对象的状态发生改变时,其所有依赖对象都能够自动收到通知并更新状态。
该模式中包含三种角色:Subject(目标对像)、Observer(观察者对像)和ConcreteObserver(具体的观察者对像)。
Subject是被观察的对象,它维护一组Observer对象,当它的状态发生变化时,会遍历这些Observer对象,并调用它们的update()方法通知它们。
Observer是观察者对象,它定义了一个接口,用于接收关于Subject状态改变的通知,并根据需要更新自己的状态。
通过使用观察者模式,可以让 Subject 与 Observer 松耦合,能够实现在不同的场景中复用 Subject 和 Observer,并且添加或删除 Observer 更加容易,同时也减少了系统的耦合度。
举个例子,假设我们正在开发一个天气预报应用程序。在该程序中,我们需要将天气状态通知给不同的用户,这些用户可能是通过短信、邮件或者App来获取信息的。
在这种情况下,我们可以将天气数据模型作为 Subject,而不同的用户(比如短信用户、邮件用户、App用户)作为 Observer。当天气数据发生改变时,Subject会通知所有 Observer,并更新其状态。
举个简单的代码例子:
// Subject
public interface WeatherData {
public void attach(Observer o);
public void detach(Observer o);
public void notifyObservers();
}
// ConcreteSubject
public class WeatherDataImpl implements WeatherData {
private List<Observer> observers;
private float temperature;
private float humidity;
private float pressure;
public WeatherDataImpl() {
observers = new ArrayList<>();
}
@Override
public void attach(Observer o) {
observers.add(o);
}
@Override
public void detach(Observer o) {
observers.remove(o);
}
@Override
public void notifyObservers() {
for (Observer o : observers) {
o.update(temperature, humidity, pressure);
}
}
public void setMeasurements(float temperature, float humidity, float pressure) {
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
measurementsChanged();
}
private void measurementsChanged() {
notifyObservers();
}
}
// Observer
public interface Observer {
public void update(float temp, float humidity, float pressure);
}
// ConcreteObserver
public class AppUser implements Observer {
private float temperature;
private float humidity;
private float pressure;
@Override
public void update(float temp, float humidity, float pressure) {
this.temperature = temp;
this.humidity = humidity;
this.pressure = pressure;
display();
}
private void display() {
System.out.println("App User: Temperature - " + temperature +
", Humidity - " + humidity + ", Pressure - " + pressure);
}
}
public class SMSUser implements Observer {
private float temperature;
private float humidity;
private float pressure;
@Override
public void update(float temp, float humidity, float pressure) {
this.temperature = temp;
this.humidity = humidity;
this.pressure = pressure;
display();
}
private void display() {
System.out.println("SMS User: Temperature - " + temperature +
", Humidity - " + humidity + ", Pressure - " + pressure);
}
}
public class WeatherStation {
public static void main(String args[]) {
WeatherData weatherData = new WeatherDataImpl();
Observer appUser = new AppUser();
Observer smsUser = new SMSUser();
weatherData.attach(appUser);
weatherData.attach(smsUser);
weatherData.setMeasurements(28, 70, 1020);
weatherData.detach(smsUser);
weatherData.setMeasurements(25, 60, 1005);
}
}
在上面的代码中,WeatherData是 Subject 接口,WeatherDataImpl是 ConcreteSubject 具体实现,AppUser 和 SMSUser 是具体的 Observer 实现。可以看到,当天气数据更新时,AppUser 和 SMSUser 都能够接收到通知并更新最新的天气数据,同时还可以随时添加或移除不同的观察者对象。
Observer Pattern 的重点包括:
定义主题(Subject)和观察者(Observer)的关系,主题维护所有已注册的观察者,当主题状态发生变化时,通知所有观察者。
主题和观察者可分别定义一个介面,让实现类别继承并实现介面方法以定义主题和观察者的行为。
观察者可注册于多个主题,当某一主题状态发生变化时,观察者即可同时收到相应的通知。
Observer Pattern 可以实现松耦合关系,主题和观察者只需维护各自的状态,彼此无需知道对方的实现细节。
主题和观察者之间的通信可以使用多种方式实现,如事件通知、回呼方法等。
实作一个订阅系统,目标物件可以让任意数量的Observer订阅,当目标物件状态改变时,通知所有Observer。
实作一个新闻发布订阅系统,资料提供者可以发布新闻讯息给所有订阅者,订阅者也可以取消订阅任意新闻类别。
实作一个股票价格监控系统,股票物件可以让许多投资者订阅,当股票价格变动时,通知订阅者。
实作一个天气预报系统,资料提供者可以在每天清晨发送当日天气预报讯息给所有订阅者,外出活动者可以根据天气预报做出安排。
实作一个订票系统,订票顾客可以订阅想要买的演唱会或活动,当有票开放购买时,通知所有订阅者。
答案:
import java.util.ArrayList;
import java.util.List;
public abstract class Subject {
private List<Observer> observers = new ArrayList<>();
public void attach(Observer observer) {
observers.add(observer);
}
public void detach(Observer observer) {
observers.remove(observer);
}
public void notifyObservers() {
for (Observer observer : observers) {
observer.update();
}
}
}
public class ConcreteSubject extends Subject {
private int state;
public int getState() {
return state;
}
public void setState(int state) {
this.state = state;
notifyObservers();
}
}
public abstract class Observer {
public abstract void update();
}
public class ConcreteObserver extends Observer {
private ConcreteSubject subject;
public ConcreteObserver(ConcreteSubject subject) {
this.subject = subject;
subject.attach(this);
}
@Override
public void update() {
System.out.println("ConcreteObserver has updated its state to " + subject.getState());
}
}
public class Main {
public static void main(String[] args) {
ConcreteSubject subject = new ConcreteSubject();
ConcreteObserver observer1 = new ConcreteObserver(subject);
ConcreteObserver observer2 = new ConcreteObserver(subject);
subject.setState(5); // expect observer1 and observer2 to print "ConcreteObserver has updated its state to 5"
}
}
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public interface Observer {
void update(String message, String category);
}
public interface Subject {
void registerObserver(Observer observer, String category);
void unregisterObserver(Observer observer, String category);
void notifyObservers(String message, String category);
}
public class NewsPublisher implements Subject {
private Map<String, List<Observer>> observersByCategory = new HashMap<>();
@Override
public void registerObserver(Observer observer, String category) {
if (!observersByCategory.containsKey(category)) {
observersByCategory.put(category, new ArrayList<>());
}
observersByCategory.get(category).add(observer);
}
@Override
public void unregisterObserver(Observer observer, String category) {
if (!observersByCategory.containsKey(category)) {
return;
}
List<Observer> observers = observersByCategory.get(category);
observers.remove(observer);
if (observers.isEmpty()) {
observersByCategory.remove(category);
}
}
@Override
public void notifyObservers(String message, String category) {
if (!observersByCategory.containsKey(category)) {
return;
}
List<Observer> observers = observersByCategory.get(category);
for (Observer observer : observers) {
observer.update(message, category);
}
}
public void publishNews(String message, String category) {
System.out.println("Publishing news: " + message);
notifyObservers(message, category);
}
}
public class NewsSubscriber implements Observer {
private String name;
public NewsSubscriber(String name) {
this.name = name;
}
@Override
public void update(String message, String category) {
System.out.println(name + " received news update for category " + category + ": " + message);
}
}
public class Main {
public static void main(String[] args) {
NewsPublisher publisher = new NewsPublisher();
NewsSubscriber subscriber1 = new NewsSubscriber("Subscriber 1");
publisher.registerObserver(subscriber1, "Politics");
NewsSubscriber subscriber2 = new NewsSubscriber("Subscriber 2");
publisher.registerObserver(subscriber2, "Sports");
publisher.publishNews("Breaking news: Election results are in.", "Politics"); // expect subscriber1 to receive message
publisher.publishNews("Sports update: Lakers win 112-105.", "Sports"); // expect subscriber2 to receive message
publisher.unregisterObserver(subscriber1, "Politics");
publisher.unregisterObserver(subscriber2, "Sports");
}
}
import java.util.ArrayList;
import java.util.List;
public interface Subject {
void registerObserver(Observer observer);
void unregisterObserver(Observer observer);
void notifyObservers();
}
public interface Observer {
void update(Stock stock);
}
public class Stock {
private String symbol;
private double price;
public Stock(String symbol, double price) {
this.symbol = symbol;
this.price = price;
}
public String getSymbol() {
return symbol;
}
public void setSymbol(String symbol) {
this.symbol = symbol;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
}
public class StockMarket implements Subject {
private List<Observer> observers = new ArrayList<>();
private List<Stock> stocks = new ArrayList<>();
@Override
public void registerObserver(Observer observer) {
observers.add(observer);
}
@Override
public void unregisterObserver(Observer observer) {
observers.remove(observer);
}
@Override
public void notifyObservers() {
for (Stock stock : stocks) {
for (Observer observer : observers) {
observer.update(stock);
}
}
}
public void addStock(Stock stock) {
stocks.add(stock);
notifyObservers();
}
public void updateStockPrice(String symbol, double price) {
for (Stock stock : stocks) {
if (stock.getSymbol().equals(symbol)) {
stock.setPrice(price);
notifyObservers();
break;
}
}
}
}
public class Investor implements Observer {
private String name;
public Investor(String name) {
this.name = name;
}
@Override
public void update(Stock stock) {
System.out.println(name + " received update for stock " + stock.getSymbol() + ": " + "price is now " + stock.getPrice());
}
}
public class Main {
public static void main(String[] args) {
StockMarket stockMarket = new StockMarket();
Stock appleStock = new Stock("AAPL", 135.50);
stockMarket.addStock(appleStock);
Investor investor1 = new Investor("Investor 1");
stockMarket.registerObserver(investor1);
stockMarket.updateStockPrice("AAPL", 136.00); // expect investor1 to receive update
stockMarket.unregisterObserver(investor1);
}
}
import java.util.ArrayList;
import java.util.List;
public interface Subject {
void registerObserver(Observer observer);
void unregisterObserver(Observer observer);
void notifyObservers();
}
public interface Observer {
void update(String forecast);
}
public class WeatherForecast implements Subject {
private List<Observer> observers = new ArrayList<>();
private String forecast;
@Override
public void registerObserver(Observer observer) {
observers.add(observer);
}
@Override
public void unregisterObserver(Observer observer) {
observers.remove(observer);
}
@Override
public void notifyObservers() {
for (Observer observer : observers) {
observer.update(forecast);
}
}
public void setForecast(String forecast) {
this.forecast = forecast;
notifyObservers();
}
}
public class OutdoorActivity implements Observer {
private String activityName;
public OutdoorActivity(String activityName) {
this.activityName = activityName;
}
@Override
public void update(String forecast) {
System.out.println(activityName + " received weather forecast: " + forecast);
if (forecast.equals("Sunny")) {
System.out.println(activityName + " is going on " + activityName + "!");
} else {
System.out.println(activityName + " is staying home.");
}
}
}
public class Main {
public static void main(String[] args) {
WeatherForecast weatherForecast = new WeatherForecast();
OutdoorActivity hiking = new OutdoorActivity("Hiking");
weatherForecast.registerObserver(hiking);
OutdoorActivity beach = new OutdoorActivity("Beach");
weatherForecast.registerObserver(beach);
weatherForecast.setForecast("Sunny"); // expect hiking and beach to receive forecast and go on activity
weatherForecast.setForecast("Rainy"); // expect hiking and beach to stay home
weatherForecast.unregisterObserver(hiking);
weatherForecast.unregisterObserver(beach);
}
}
import java.util.ArrayList;
import java.util.List;
public interface Subject {
void registerObserver(Observer observer);
void unregisterObserver(Observer observer);
void notifyObservers();
}
public interface Observer {
void update(String event);
}
public class TicketSystem implements Subject {
private List<Observer> observers = new ArrayList<>();
private List<String> availableEvents = new ArrayList<>();
@Override
public void registerObserver(Observer observer) {
observers.add(observer);
}
@Override
public void unregisterObserver(Observer observer) {
observers.remove(observer);
}
@Override
public void notifyObservers() {
for (Observer observer : observers) {
observer.update("New tickets available!");
}
}
public void addEvent(String event) {
availableEvents.add(event);
}
public void openTicketSales(String event) {
availableEvents.remove(event);
notifyObservers();
}
}
public class Customer implements Observer {
private String name;
public Customer(String name) {
this.name = name;
}
@Override
public void update(String event) {
System.out.println(name + " received ticket update: " + event);
}
}
public class Main {
public static void main(String[] args) {
TicketSystem ticketSystem = new TicketSystem();
ticketSystem.addEvent("Concert");
ticketSystem.addEvent("Musical");
Customer customer1 = new Customer("Customer 1");
ticketSystem.registerObserver(customer1);
Customer customer2 = new Customer("Customer 2");
ticketSystem.registerObserver(customer2);
ticketSystem.openTicketSales("Musical"); // expect customer1 and customer2 to receive update
ticketSystem.unregisterObserver(customer1);
ticketSystem.unregisterObserver(customer2);
}
}