首页 > 数据库 > 数据库开发技术 > 行为型设计模式(五):访问者模式 & 观察者模式

访问者模式允许定义一些不改变数据结构的前提下的操作。通过这种方式,可以在不修改元素类的情况下定义新的操作。访问者模式常用于对复杂对象结构进行操作,而又不希望在这些对象上破坏封装性。
访问者模式将数据结构和操作分离,使得新增操作更加灵活,而不影响数据结构。
可以通过定义新的访问者来增加新的操作,而无需修改元素类,可扩展性强
设计实现一个图形编辑器,包含不同图形类型和对应的不同的操作
// 抽象元素类interface Shape {void accept(Visitor visitor);}// 具体元素类1:圆形class Circle implements Shape {private int radius;Circle(int radius) {this.radius = radius;}public int getRadius() {return radius;}public void accept(Visitor visitor) {visitor.visit(this);}}// 具体元素类2:矩形class Rectangle implements Shape {private int width;private int height;Rectangle(int width, int height) {this.width = width;this.height = height;}public int getWidth() {return width;}public int getHeight() {return height;}public void accept(Visitor visitor) {visitor.visit(this);}}// 抽象访问者interface Visitor {void visit(Circle circle);void visit(Rectangle rectangle);}// 具体访问者1:移动操作class MoveVisitor implements Visitor {private int deltaX;private int deltaY;MoveVisitor(int deltaX, int deltaY) {this.deltaX = deltaX;this.deltaY = deltaY;}public void visit(Circle circle) {System.out.println("Moving circle with radius " + circle.getRadius() + " by (" + deltaX + ", " + deltaY + ")");}public void visit(Rectangle rectangle) {System.out.println("Moving rectangle with width " + rectangle.getWidth() + " and height " + rectangle.getHeight() + " by (" + deltaX + ", " + deltaY + ")");}}// 具体访问者2:缩放操作class ScaleVisitor implements Visitor {private double scaleFactor;ScaleVisitor(double scaleFactor) {this.scaleFactor = scaleFactor;}public void visit(Circle circle) {System.out.println("Scaling circle with radius " + circle.getRadius() + " by factor " + scaleFactor);}public void visit(Rectangle rectangle) {System.out.println("Scaling rectangle with width " + rectangle.getWidth() + " and height " + rectangle.getHeight() + " by factor " + scaleFactor);}}// 客户端代码public class Client {public static void main(String[] args) {Shape circle = new Circle(5);Shape rectangle = new Rectangle(10, 8);Visitor moveVisitor = new MoveVisitor(2, 3);Visitor scaleVisitor = new ScaleVisitor(1.5);// 执行移动操作circle.accept(moveVisitor);rectangle.accept(moveVisitor);// 执行缩放操作circle.accept(scaleVisitor);rectangle.accept(scaleVisitor);}}
如果系统中新增了一个元素类,所有的具体访问者类都需要修改,不符合开闭原则。
可以通过引入抽象访问者,将新增元素类的访问方法定义在抽象访问者中,然后具体访问者类只需要实现必要的访问方法。
观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听一个主题对象。当主题对象状态发生变化时,所有依赖它的观察者都会得到通知并自动更新。
观察者模式实现了发布者和订阅者之间的松耦合,使得它们可以独立变化,不影响彼此。
新的观察者可以随时加入,而不影响发布者的实现,可扩展性强。
设计实现一个简单的新闻订阅系统,其中有多个订阅者订阅不同类型的新闻
import java.util.ArrayList;import java.util.List;// 主题接口interface Subject {void addObserver(Observer observer);void removeObserver(Observer observer);void notifyObservers(String news);}// 具体主题:新闻发行class NewsPublisher implements Subject {private List<Observer> observers;NewsPublisher() {this.observers = new ArrayList<>();}public void addObserver(Observer observer) {observers.add(observer);}public void removeObserver(Observer observer) {observers.remove(observer);}public void notifyObservers(String news) {for (Observer observer : observers) {observer.update(news);}}}// 观察者接口interface Observer {void update(String news);}// 具体观察者1:普通订阅者class RegularSubscriber implements Observer {private String name;RegularSubscriber(String name) {this.name = name;}public void update(String news) {System.out.println(name + " received regular news: " + news);}}// 具体观察者2:紧急订阅者class UrgentSubscriber implements Observer {private String name;UrgentSubscriber(String name) {this.name = name;}public void update(String news) {System.out.println(name + " received urgent news: " + news);}}// 客户端代码public class Client {public static void main(String[] args) {// 创建新闻发行主题NewsPublisher newsPublisher = new NewsPublisher();// 创建订阅者Observer regularSubscriber1 = new RegularSubscriber("Alice");Observer regularSubscriber2 = new RegularSubscriber("Bob");Observer urgentSubscriber = new UrgentSubscriber("Charlie");// 订阅者订阅主题newsPublisher.addObserver(regularSubscriber1);newsPublisher.addObserver(regularSubscriber2);newsPublisher.addObserver(urgentSubscriber);// 发布新闻newsPublisher.notifyObservers("Important news: COVID-19 vaccine breakthrough!");newsPublisher.notifyObservers("Regular news: Weather forecast for the week");// 移除一个订阅者newsPublisher.removeObserver(regularSubscriber2);// 再次发布新闻newsPublisher.notifyObservers("Urgent news: Emergency evacuation due to natural disaster!");}}
在观察者模式中,观察者的更新顺序是不确定的,可能导致一些依赖顺序的问题。
通知模式比较单一,通知观察者的方式是同步的,如果某个观察者的更新操作耗时较长,可能影响整体性能。
可以使用队列将观察者的更新操作异步执行,避免影响主题的通知效率。
可以引入顺序控制机制,明确观察者的更新顺序。
原文作者:灸哥漫谈;如有侵权,请联系管理员删除。