设计模式之-观察者模式,快速掌握观察者模式,通俗易懂的讲解观察者模式以及它的使用场景


一、快速理解观察者模式

当谈到设计模式中的观察者模式(Observer Pattern)时,它是一种行为型设计模式,用于在对象之间建立一种一对多的依赖关系,当一个对象的状态发生改变时,它的所有依赖者都会得到通知并自动更新。

通俗地说,观察者模式就像是一个主题(被观察者)和一群订阅者(观察者)之间的关系。主题维护一个订阅者列表,当主题状态发生变化时,它会通知所有的订阅者进行相应的更新操作。

二、观察者模式适用场景

  1. 当一个对象的改变需要同时改变其他对象,并且你不知道有多少对象需要改变时。
  2. 当一个对象需要将自己的改变通知给其他对象,而又不希望与其紧密耦合时。

三、观察者模式优缺点

观察者模式的优点包括:

  • 解耦:观察者模式将主题和观察者解耦,使它们可以独立变化,互不影响。
  • 扩展性:可以灵活地添加新的观察者,或者改变观察者的行为,而无需修改主题的代码。
  • 维护一致性:主题和观察者之间建立了一种松散的依赖关系,保证了一致性。

观察者模式的缺点包括:

  • 过多的通知:当主题对象有大量的观察者时,每次状态变化都需要通知所有观察者,可能会造成性能问题。
  • 循环引用:当观察者之间相互引用时,可能导致循环引用的问题,需要注意避免。

总结来说,观察者模式适用于需要实现对象间的动态一对多关系,并且希望避免紧耦合的场景。它可以帮助我们实现松散耦合的设计,提高代码的可维护性和扩展性。

四、代码示例

面是一个简单的示例代码来说明观察者模式的实现:

import java.util.ArrayList;
import java.util.List;

// 主题接口
interface Subject {
    void attach(Observer observer); // 添加观察者
    void detach(Observer observer); // 移除观察者
    void notifyObservers(); // 通知观察者
}

// 具体主题类
class ConcreteSubject implements Subject {
    private List<Observer> observers = new ArrayList<>();
    private int state;
    
    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 int getState() {
        return state;
    }
    
    public void setState(int state) {
        this.state = state;
        notifyObservers(); // 状态变化时通知观察者
    }
}

// 观察者接口
interface Observer {
    void update();
}

// 具体观察者类
class ConcreteObserver implements Observer {
    private ConcreteSubject subject;
    
    public ConcreteObserver(ConcreteSubject subject) {
        this.subject = subject;
        subject.attach(this); // 注册观察者
    }
    
    public void update() {
        int state = subject.getState();
        // 执行相应的操作
        System.out.println("观察者收到通知,当前状态为:" + state);
    }
}

// 示例代码
public class ObserverPatternExample {
    public static void main(String[] args) {
        ConcreteSubject subject = new ConcreteSubject();
        ConcreteObserver observer1 = new ConcreteObserver(subject);
        ConcreteObserver observer2 = new ConcreteObserver(subject);
        
        subject.setState(1);
        subject.setState(2);
    }
}

在上述示例中,主题(ConcreteSubject)维护了一个观察者列表,并提供了添加、移除和通知观察者的方法。观察者(ConcreteObserver)实现了观察者接口,并在构造函数中将自身注册到主题中。当主题状态发生变化时,它会遍历观察者列表,并调用每个观察者的 update() 方法来进行相应的操作。

五、我们来听一个故事,加深理解

假设有一个小镇,这个小镇上有一家天气预报中心。每天早上,天气预报中心会发布当天的天气情况,包括温度、湿度、风力等信息。同时,小镇上的几个居民对天气情况非常关注,因为天气会影响他们的日常生活。

在这个故事中,天气预报中心是被观察者(主题),而居民们是观察者。他们想要根据天气情况来做出相应的安排,比如选择穿什么衣服、是否要带伞等。

现在,我们来看一下如何使用观察者模式来实现这个故事。

首先,我们需要定义一个主题(WeatherCenter)接口,其中包含了添加观察者、移除观察者和通知观察者的方法。

interface WeatherCenter {
    void addObserver(Observer observer);
    void removeObserver(Observer observer);
    void notifyObservers();
}

然后,我们定义一个具体的天气预报中心(ConcreteWeatherCenter)类,实现了主题接口,并维护了一个观察者列表。

class ConcreteWeatherCenter implements WeatherCenter {
    private List<Observer> observers = new ArrayList<>();
    private WeatherData weatherData;
    
    public void addObserver(Observer observer) {
        observers.add(observer);
    }
    
    public void removeObserver(Observer observer) {
        observers.remove(observer);
    }
    
    public void notifyObservers() {
        for (Observer observer : observers) {
            observer.update(weatherData);
        }
    }
    
    public void setWeatherData(WeatherData weatherData) {
        this.weatherData = weatherData;
        notifyObservers();
    }
}

接下来,我们定义一个观察者(Resident)接口,其中包含了更新方法。

interface Observer {
    void update(WeatherData weatherData);
}

然后,我们定义一个具体的居民(ConcreteResident)类,实现了观察者接口。

class ConcreteResident implements Observer {
    private String name;
    
    public ConcreteResident(String name) {
        this.name = name;
    }
    
    public void update(WeatherData weatherData) {
        // 根据天气情况做出相应的安排
        System.out.println(name + "收到天气预报,今天的温度是:" + weatherData.getTemperature() + "℃");
    }
}

最后,我们来看一下如何将这些角色组合起来并运行起来。

public class ObserverPatternStory {
    public static void main(String[] args) {
        ConcreteWeatherCenter weatherCenter = new ConcreteWeatherCenter();
        
        ConcreteResident resident1 = new ConcreteResident("John");
        weatherCenter.addObserver(resident1);
        
        ConcreteResident resident2 = new ConcreteResident("Alice");
        weatherCenter.addObserver(resident2);
        
        WeatherData weatherData = new WeatherData(25); // 假设温度为25℃
        weatherCenter.setWeatherData(weatherData);
    }
}

在这个故事中,天气预报中心是主题,居民们是观察者。当天气预报中心发布天气信息时,所有的居民都会收到通知,并根据天气情况做出相应的安排。

这个故事中的观察者模式展示了一个实际生活中常见的场景。通过观察者模式,天气预报中心和居民之间建立了一种松散的依赖关系,使得天气预报中心能够方便地通知居民们最新的天气情况,居民们也能够根据天气情况做出适当的调整。

故事中的观察者模式的优点是:

天气预报中心和居民之间实现了解耦,它们可以独立变化,互不影响。
天气预报中心可以方便地添加或移除观察者,居民们也可以灵活地订阅或取消订阅天气通知。
天气预报中心发布天气信息时,所有的居民都能够及时收到通知,确保信息的一致性。
观察者模式的缺点在这个故事中并不明显,但在实际应用中可能存在以下问题:

如果观察者过多或者观察者执行的操作较为耗时,可能会导致性能问题。
观察者之间相互引用时,可能出现循环引用的问题,需要注意避免。
总结来说,观察者模式在实际应用中非常有用,可以帮助我们实现对象之间的一对多关系,实现解耦、灵活性和一致性。无论是天气预报、事件通知还是其他需要实现观察者和被观察者之间关系的场景,观察者模式都是一个强大的工具。

  • 37
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,关于Java的设计模式,常见的有23种,其中比较常用的包括单例模式、工厂模式、观察者模式等等。这里举个例子来说明一下工厂模式的应用。 工厂模式是用来创建对象的一种模式,它提供了一种创建对象的最佳方式。例如,我们有一个工厂类,它有一个方法可以根据传入的参数来创建不同的对象,这样我们就可以将对象的创建逻辑从客户端代码中分离出来。下面是一个简单的例子: 我们有一个披萨店,它可以制作不同种类的披萨,比如意大利披萨、希腊披萨、墨西哥披萨等等。我们可以创建一个工厂类,它有一个方法可以根据传入的参数来创建不同种类的披萨对象。客户端代码只需要调用工厂方法即可获得所需的披萨对象,而不需要关心具体的创建过程。 具体实现可以参考以下代码: 首先,我们定义一个抽象的Pizza类,它包含了一些公共的方法,比如getName()和prepare()等: public abstract class Pizza { protected String name; public abstract void prepare(); public String getName() { return name; } } 然后,我们定义不同种类的Pizza类,比如意大利披萨、希腊披萨和墨西哥披萨等: public class ItalianPizza extends Pizza { public ItalianPizza() { name = "意大利披萨"; } public void prepare() { System.out.println("准备意大利披萨的材料"); } } public class GreekPizza extends Pizza { public GreekPizza() { name = "希腊披萨"; } public void prepare() { System.out.println("准备希腊披萨的材料"); } } public class MexicanPizza extends Pizza { public MexicanPizza() { name = "墨西哥披萨"; } public void prepare() { System.out.println("准备墨西哥披萨的材料"); } } 最后,我们创建一个工厂类,它有一个方法可以根据传入的参数来创建不同种类的Pizza对象: public class PizzaFactory { public Pizza createPizza(String type) { if (type.equals("Italian")) { return new ItalianPizza(); } else if (type.equals("Greek")) { return new GreekPizza(); } else if (type.equals("Mexican")) { return new MexicanPizza(); } else { return null; } } } 客户端代码可以这样调用工厂方法来获得所需的Pizza对象: PizzaFactory factory = new PizzaFactory(); Pizza pizza1 = factory.createPizza("Italian"); Pizza pizza2 = factory.createPizza("Greek"); Pizza pizza3 = factory.createPizza("Mexican"); 通过工厂模式,我们可以将对象的创建过程抽象出来,使客户端代码更加清晰简洁。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值