设计模式-观察者模式(Observer Pattern)-ALOOGY WORLD (aloogychendl23.asia)
观察者模式的应用
观察者模式(Observer Pattern)是一种行为型设计模式,用于在对象之间建立一对多的依赖关系,当一个对象的状态发生变化时,其相关依赖对象会自动收到通知并进行相应处理。
一、概念
观察者模式(又被称为发布-订阅(Publish/Subscribe)模式,属于行为型模式的一种,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态变化时,会通知所有的观察者对象,使他们能够自动更新自己。
二、观察者模式适用场景
-
当一个对象的改变需要同时通知其他对象,并且你不知道有多少对象需要被通知时,可以使用观察者模式。它将这种一对多的依赖关系进行了解耦,使得主题对象和观察者对象之间松耦合。
-
当一个对象的改变需要触发其他对象的特定行为时,可以使用观察者模式。观察者可以根据主题对象的状态变化来执行相应的操作,实现了对象之间的交互和协作。
-
当应用中的某个对象需要与多个其他对象进行交互,但又希望避免紧密耦合时,可以使用观察者模式。观察者模式使得主题对象和观察者对象之间只依赖于抽象接口,减少了对象间的直接依赖,提高了系统的灵活性和可扩展性。
三、优点
-
解耦合:将主题与具体观察者解耦,使得它们可以独立地变化和复用。
-
扩展性:易于添加新的观察者以及定义新的事件类型。
-
实时性:实现了实时更新机制,当主题状态改变时能够即刻通知相关观察者
四、缺点
-
过度使用可能导致性能问题和复杂度增加。
-
触发链问题:如果观察者之间有依赖关系,那么通知链可能会导致不可预料的结果。
五、观察者模式的构成
-
Subject(主题)
:也称为被观察者或可观察者,它维护了一组观察者,并提供了用于添加、删除和通知观察者的方法。当其状态发生变化时,会通知所有观察者。
-
Observer(观察者)
:也称为订阅者或监听者,它定义了一个更新接口,用于接收主题的通知。当观察者接收到通知时,可以执行相应的操作。
主题(Subject):也称为被观察者或可观察者,它是具有状态的对象,并维护着一个观察者列表。主题提供了添加、删除和通知观察者的方法。
观察者(Observer):观察者是接收主题通知的对象。观察者需要实现一个更新方法,当收到主题的通知时,调用该方法进行更新操作。
具体主题(Concrete Subject):具体主题是主题的具体实现类。它维护着观察者列表,并在状态发生改变时通知观察者。
具体观察者(Concrete Observer):具体观察者是观察者的具体实现类。它实现了更新方法,定义了在收到主题通知时需要执行的具体操作。
六、观察者模式的实现方式
定义观察者接口:包含一个更新方法。
创建具体观察者:实现观察者接口,定义接收到通知时的行为。
定义主题接口:包含添加、删除和通知观察者的方法。
创建具体主题:实现主题接口,管理观察者列表,并在状态改变时通知它们。
七、应用实例(源码分享)
1.演示示例
-
创建 Subject 类
//Subject.java import java.util.ArrayList; import java.util.List; public class Subject { private List<Observer> observers = new ArrayList<Observer>(); private int state; public int getState() { return state; } public void setState(int state) { this.state = state; notifyAllObservers(); } public void attach(Observer observer){ observers.add(observer); } public void notifyAllObservers(){ for (Observer observer : observers) { observer.update(); } } }
-
创建 Observer 类
//Observer.java public abstract class Observer { protected Subject subject; public abstract void update(); }
-
创建实体观察者类
//BinaryObserver.java public class BinaryObserver extends Observer{ public BinaryObserver(Subject subject){ this.subject = subject; this.subject.attach(this); } @Override public void update() { System.out.println( "Binary String: " + Integer.toBinaryString( subject.getState() ) ); } }
//OctalObserver.java public class OctalObserver extends Observer{ public OctalObserver(Subject subject){ this.subject = subject; this.subject.attach(this); } @Override public void update() { System.out.println( "Octal String: " + Integer.toOctalString( subject.getState() ) ); } }
//HexaObserver.java public class HexaObserver extends Observer{ public HexaObserver(Subject subject){ this.subject = subject; this.subject.attach(this); } @Override public void update() { System.out.println( "Hex String: " + Integer.toHexString( subject.getState() ).toUpperCase() ); } }
-
使用 Subject 和实体观察者对象
//ObserverPatternDemo.java public class ObserverPatternDemo { public static void main(String[] args) { Subject subject = new Subject(); new HexaObserver(subject); new OctalObserver(subject); new BinaryObserver(subject); System.out.println("First state change: 15"); subject.setState(15); System.out.println("Second state change: 10"); subject.setState(10); } }
-
执行程序,输出结果:
First state change: 15 Hex String: F Octal String: 17 Binary String: 1111 Second state change: 10 Hex String: A Octal String: 12 Binary String: 1010
2.具体实例
用观察者模式实现: 网上商店中如果商品(product)在名称(name)、价格(price)、产地(address)等方面有变化,系统能自动把变化了的信息通知会员,这将是网上商店区别传统商店的一大特色。画出类关系图(UML图)并编程实现。
-
定义具体目标类
// ConcreteProduct.java public class ConcreteProduct extends Product { private String name; private double price; private String address; public ConcreteProduct(String name, double price, String address) { super(name); this.name = name; this.price = price; this.address = address; } @Override public void setName(String name) { this.name = name; notifyObservers("Name changed to: " + name); } @Override public void setPrice(double price) { this.price = price; notifyObservers("Price changed to: $" + price); } @Override public void setAddress(String address) { this.address = address; notifyObservers("Address changed to: " + address); } // 获取产品名称 public String getName() { return name; } // 获取产品价格 public double getPrice() { return price; } // 获取产品地址 public String getAddress() { return address; } }
-
定义具体观察者类
// Member.java public class Member implements Observer { private String name; public Member(String name) { this.name = name; } @Override public void update(String productName, String message) { System.out.printf("Member: %-10s | Product: %-15s | Update: %s%n", name, productName, message); } // 获取会员名称 public String getName() { return name; } }
-
观察者接口
public interface Observer { void update(String productName, String message); }
-
定义目标接口
import java.util.ArrayList; import java.util.List; public abstract class Product { private List<Observer> observers = new ArrayList<>(); private String productName; public Product(String productName) { this.productName = productName; } // 添加观察者 public void addObserver(Observer observer) { observers.add(observer); System.out.printf("Observer added: %s for Product: %s%n", ((Member) observer).getName(), productName); } // 移除观察者 public void removeObserver(Observer observer) { observers.remove(observer); System.out.printf("Observer removed: %s for Product: %s%n", ((Member) observer).getName(), productName); } // 通知所有观察者 protected void notifyObservers(String message) { for (Observer observer : observers) { observer.update(productName, message); } } // 抽象方法,供具体产品实现 public abstract void setName(String name); public abstract void setPrice(double price); public abstract void setAddress(String address); }
-
创建具体产品和会员,并模拟产品信息的变化。(具体观察者)
// ObserverPatternTest.java public class ObserverPatternTest { public static void main(String[] args) { // 创建具体产品 ConcreteProduct laptop = new ConcreteProduct("Laptop", 1500.00, "China"); ConcreteProduct camera = new ConcreteProduct("Camera", 500.00, "Japan"); // 创建具体观察者(会员) Member alice = new Member("Aloogy"); Member bob = new Member("Yumi"); // 注册观察者 laptop.addObserver(alice); laptop.addObserver(bob); camera.addObserver(alice); // 模拟产品信息变化 System.out.println("\nChanging Laptop details:"); laptop.setName("Gaming Laptop"); laptop.setPrice(2000.00); System.out.println("\nChanging Camera details:"); camera.setAddress("South Korea"); camera.setPrice(600.00); // 移除观察者并再次更改信息 laptop.removeObserver(bob); System.out.println("\nChanging Laptop details after removing an observer:"); laptop.setName("Ultra Gaming Laptop"); laptop.setPrice(2500.00); } }
-
输出结果:
-
UML