行为型设计模式(五):访问者模式 & 观察者模式

行为型设计模式(五):访问者模式 & 观察者模式_第1张图片

访问者模式 Visitor

1、什么是访问者模式

访问者模式允许定义一些不改变数据结构的前提下的操作。通过这种方式,可以在不修改元素类的情况下定义新的操作。访问者模式常用于对复杂对象结构进行操作,而又不希望在这些对象上破坏封装性。

2、为什么使用访问者模式

  1. 访问者模式将数据结构和操作分离,使得新增操作更加灵活,而不影响数据结构。
  2. 可以通过定义新的访问者来增加新的操作,而无需修改元素类,可扩展性强

3、如何使用访问者模式

设计实现一个图形编辑器,包含不同图形类型和对应的不同的操作

// 抽象元素类
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;
    }

    @Override
    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;
    }

    @Override
    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;
    }

    @Override
    public void visit(Circle circle) {
        System.out.println("Moving circle with radius " + circle.getRadius() + " by (" + deltaX + ", " + deltaY + ")");
    }

    @Override
    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;
    }

    @Override
    public void visit(Circle circle) {
        System.out.println("Scaling circle with radius " + circle.getRadius() + " by factor " + scaleFactor);
    }

    @Override
    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);
    }
}

4、是否存在缺陷和不足

如果系统中新增了一个元素类,所有的具体访问者类都需要修改,不符合开闭原则。

5、如何缓解缺陷和不足

可以通过引入抽象访问者,将新增元素类的访问方法定义在抽象访问者中,然后具体访问者类只需要实现必要的访问方法。

观察者模式 Observer

1、什么是观察者模式

观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听一个主题对象。当主题对象状态发生变化时,所有依赖它的观察者都会得到通知并自动更新。

2、为什么使用观察者模式

  1. 观察者模式实现了发布者和订阅者之间的松耦合,使得它们可以独立变化,不影响彼此。
  2. 新的观察者可以随时加入,而不影响发布者的实现,可扩展性强。

3、如何使用观察者模式

设计实现一个简单的新闻订阅系统,其中有多个订阅者订阅不同类型的新闻

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 observers;

    NewsPublisher() {
        this.observers = new ArrayList<>();
    }

    @Override
    public void addObserver(Observer observer) {
        observers.add(observer);
    }

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

    @Override
    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;
    }

    @Override
    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;
    }

    @Override
    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!");
    }
}

4、是否存在缺陷和不足

  1. 在观察者模式中,观察者的更新顺序是不确定的,可能导致一些依赖顺序的问题。
  2. 通知模式比较单一,通知观察者的方式是同步的,如果某个观察者的更新操作耗时较长,可能影响整体性能。

5、如何缓解缺陷和不足

  1. 可以使用队列将观察者的更新操作异步执行,避免影响主题的通知效率。
  2. 可以引入顺序控制机制,明确观察者的更新顺序。

你可能感兴趣的:(技术专项能力,设计模式,访问者模式,观察者模式)