设计模式——(十一)观察者模式

观察者模式(Publish/Subscribe)

背景:老板回来,前台通知大家,但老板和前台一起,就没法通知了
1.经典做法。前台类:里面有在她这里注册的观察者。老板回来了,发送消息给注册过的人。看股票者,需要知道前台类,前台类通知了,采取的方法。两个类耦合太强。都需要彼此知道,若增加一个看NBA者,则需要修改三个类。
2.好点的做法,看股票者,看NBA者抽象一个类,前台只要知道抽象的类就可以了。但观察者类中还有前台,若前台换人了,老板来了没人通知。老板前台都是通知者,也可以抽象一个类。
在这里插入图片描述
观察者模式又叫发布订阅模式,定义了一种一对多的依赖关系,让多个观察者对象,同时监听某一主题对象。这个主题对象的状态发生变化时,会通知所有观察者对象,使他们能够自动更新自己。

UML结构图

在这里插入图片描述
Subject类,抽象通知者(主题),一般用一个抽象类或者一个接口实现。
Observer类,抽象观察者,一般用一个抽象类或者一个接口实现。更新接口通常包含一个Update方法。
ConcreteSubject具体通知者(具体主题)。具体主题角色通常用一个具体的子类实现。
ConcreteOberver 具体观察者角色。可以保存一个指向具体主题对象的引用。具体观察者角色通常用一个具体的子类实现。

C++代码实现

/抽象观察者
class Observer {
public:
    virtual void Update() {}
};
//抽象通知者
class Subject {
private:
    vector<Observer*> m_Observers;   //要用指针 ,变量不行
public:
    //增加观察者
    virtual void add(Observer *ob)
    {
        m_Observers.push_back(ob);
    }
    //移除观察者(移除最后一个)
    virtual void remove()
    {
        m_Observers.pop_back();
    }
    //通知所有人
    void Notify() 
    {
        for(int i=0;i< m_Observers.size(); i++)
        {
            m_Observers.at(i)->Update();
        }
    }
};
//具体通知者
class ConcreteSubject :public Subject {
private:
    string m_status; // 具体被观察者的状态
public:
    void setStatus(string str)
    {
        m_status = str;
    }
    string getStatus()
    {
        return m_status;
    }
};
//具体观察者
class ConcreteObserver:public Observer {
public:
    ConcreteObserver(ConcreteSubject *cs, string str)
    {
        m_creteSubject = cs;
        m_name = str;
    }
    void Update() 
    {
        m_observerSatus = m_creteSubject->getStatus();
        cout << "观察者:" << m_name << " status is : " << m_observerSatus << endl;
    }
    void setSubject(ConcreteSubject *cs)
    {
        m_creteSubject = cs;
    }
    ConcreteSubject* getSubject()
    {
        return m_creteSubject;
    }
private:
    string m_name;
    string m_observerSatus; 
    ConcreteSubject *m_creteSubject; //具体通知者的引用  一定得是引用或者指针
};
int main()
{
    std::cout << "Hello World!\n";
    ConcreteSubject * tzz =new  ConcreteSubject();//通知者
    tzz->add( new ConcreteObserver(tzz, "wth"));    //将观察者加入通知者的通知人中
    tzz->add(new  ConcreteObserver(tzz, "zzz"));
    tzz->add(new  ConcreteObserver(tzz, "Qpc"));

    tzz->setStatus("onwork");  //通知者状态
    tzz->Notify();//通知

    tzz->remove();
    tzz->Notify();//通知
}

3.用观察者模式得动机:将一个系统分割成一系列相互协作得类有个很不好得副作用,那就是需要维护相关对象得一致性。我们不希望为了维持一致性而使各个类紧密耦合,这样会给维护,扩展,和重用都带来不便。
观察者模式的关键对象subject和observer。一个subject可以有任意数目依赖它的Observer。一旦Subject的状态发生了改变,所有的observer都会得到具体的通知。发通知时不需要知道谁是它的观察者。而任何一个具体的观察者不需要也不知道其它观察者的存在。
4.何时使用:当一个对象的改变,需要同时改变其它对象的时候。而且他不知道具体有多少对象有待改变时可以使用观察者模式。
当一个抽象模型有两个方面,其中一个方面依赖另一个方面,这时用观察者模式可以将这两个封装在独立的对象中使他们各自独立的改变和复用。
总的来说观察者模式所做的工作就是在解除耦合。让耦合的双方都依赖于抽象。而不是依赖于具体。从而使得各自的变化都不会影响另一边的变化。(依赖倒转原则的最佳体现)
5.抽象观察者时用的抽象类。实际中具体的抽象观察者时完全没关系的类,无法抽象。因此可以用一下接口。
Interface Observer{
Void Update();
}如何实现Observer接口?
6.观察者模式不足:使用vs2019点击运行,界面会变化,菜单栏,自动变量等窗口弹出。没有办法让每个控件都去实现一个observer 窗口,因为控件都早已经被制造商封装了。不可能用的接口方法。抽象通知者还是依赖抽象观察者。另外每个具体的观察者也不是同名的update方法调用。如果通知者和观察者之间根本互相不知道,由客户端来决定通知谁。(使用事件委托,注册对应的事件,点运行时,同时运行)

事件委托实现

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

说明:委托就是一种引用方法的类型。一旦委托分配了方法,委托将具有与该方法完全相同的行为。委托方法的使用可以像其它任意方法一样,具有参数和返回值。委托可以看做是对函数的抽象,是函数的类,委托的实例将代表一个具体的函数。
① Delegete void EventHandler();可以理解为一个特殊的类。
② Public event EventHandler Update;声明一个类的变量(声明了一个事件委托变量叫更新)
③ New Eventhandler(tongshi1.CloseStockMarket)即一个委托的实例,等于将tongshi1.CloseStockMarket这个方法委托给Update了。
④ 一个委托可以搭载多种方法,所有方法被依次唤起。最重要的是,它可以使委托对象所搭载的方法并不属于同一个类。
解决了与抽象观察者的耦合问题。
委托的前提:委托对象所搭载的所有方法必须具有相同的原型和形式,即相同的参数列表和返回值类型。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
观察者模式是一种常见的设计模式,它定义了一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖它的对象都会得到通知并自动更新。在这个模式,被观察者对象通常称为主题(Subject),而观察者对象通常称为观察者(Observer)。 下面我们就以一个简单的天气预报系统为例来介绍观察者模式的使用。 首先,我们需要定义一个主题接口(Subject),它包含了添加、删除和通知观察者的方法: ```java public interface Subject { public void registerObserver(Observer o); public void removeObserver(Observer o); public void notifyObservers(); } ``` 然后,我们需要定义一个观察者接口(Observer),它包含了更新数据的方法: ```java public interface Observer { public void update(float temp, float humidity, float pressure); } ``` 接下来,我们需要定义一个具体的主题(WeatherData),它实现了主题接口,并包含了一个列表来存储观察者对象,以及当前的温度、湿度和气压等数据: ```java import java.util.ArrayList; public class WeatherData implements Subject { private ArrayList<Observer> observers; private float temperature; private float humidity; private float pressure; public WeatherData() { observers = new ArrayList<Observer>(); } public void registerObserver(Observer o) { observers.add(o); } public void removeObserver(Observer o) { int i = observers.indexOf(o); if (i >= 0) { observers.remove(i); } } public void notifyObservers() { for (int i = 0; i < observers.size(); i++) { Observer observer = (Observer)observers.get(i); observer.update(temperature, humidity, pressure); } } public void measurementsChanged() { notifyObservers(); } public void setMeasurements(float temperature, float humidity, float pressure) { this.temperature = temperature; this.humidity = humidity; this.pressure = pressure; measurementsChanged(); } // other WeatherData methods here } ``` 最后,我们需要定义一个具体的观察者(CurrentConditionsDisplay),它实现了观察者接口,并在更新数据时打印出当前的温度、湿度和气压等信息: ```java public class CurrentConditionsDisplay implements Observer { private float temperature; private float humidity; private Subject weatherData; public CurrentConditionsDisplay(Subject weatherData) { this.weatherData = weatherData; weatherData.registerObserver(this); } public void update(float temperature, float humidity, float pressure) { this.temperature = temperature; this.humidity = humidity; display(); } public void display() { System.out.println("Current conditions: " + temperature + "F degrees and " + humidity + "% humidity"); } } ``` 现在,我们可以创建一个天气预报系统,它包含了一个主题对象和一个观察者对象,并通过调用主题对象的方法来更新数据和通知观察者: ```java public class WeatherStation { public static void main(String[] args) { WeatherData weatherData = new WeatherData(); CurrentConditionsDisplay currentDisplay = new CurrentConditionsDisplay(weatherData); weatherData.setMeasurements(80, 65, 30.4f); weatherData.setMeasurements(82, 70, 29.2f); weatherData.setMeasurements(78, 90, 29.2f); } } ``` 以上就是一个简单的观察者模式的例子,它可以让我们更好地理解和应用这个常见的设计模式

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值